diff --git a/.planfile/sprints/current.yaml b/.planfile/sprints/current.yaml index bbc4a48..ddc0668 100644 --- a/.planfile/sprints/current.yaml +++ b/.planfile/sprints/current.yaml @@ -2222,19 +2222,18 @@ sprint: key: semcod/tagi#134 url: https://github.com/semcod/tagi/issues/134 updated_at: '2026-09-18T16:49:07.642356+00:00' - PLF-135: + PLF-138: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-18T19:36:57.323254+00:00' - description: ' + created_at: '2026-09-18T19:51:27.884743+00:00' + description: ' - code2llm reports `Shotgun Surgery: builder` in `src/tagi/utils/summary_helpers.py:71`. + code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. - Mutation of variable ''builder'' spans 11 functions. Changing this logic requires - work in many places. + Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. Make the smallest refactor that removes the smell and run local tests.' @@ -2246,59 +2245,57 @@ sprint: executor: kind: human mode: interactive - external_id: '140' + external_id: '143' files: - src/tagi/utils/summary_helpers.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: builder` in `src/tagi/utils/summary_helpers.py:71`. + message: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. - Mutation of variable ''builder'' spans 11 functions. Changing this logic - requires work in many places. + Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-18T19:36:57.323254+00:00' - id: PLF-135 + timestamp: '2026-09-18T19:51:27.884743+00:00' + id: PLF-138 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: builder` in `src/tagi/utils/summary_helpers.py:71`. + prompt: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. - Mutation of variable ''builder'' spans 11 functions. Changing this logic - requires work in many places. + Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - god-function metadata: - deduplication_key: PLF-135 - name: 'Address code smell: Shotgun Surgery: builder' + deduplication_key: PLF-138 + name: 'Address code smell: God Function: build_statistics_section' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/utils/summary_helpers.py:71:Shotgun - Surgery: builder' + dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/summary_helpers.py:31:God + Function: build_statistics_section' evidence: artifact: mtime_ns: 1789760212841277131 @@ -2323,38 +2320,37 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: builder` in `src/tagi/utils/summary_helpers.py:71`. + input: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. - Mutation of variable ''builder'' spans 11 functions. Changing this logic - requires work in many places. + Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-18T19:36:57.323254+00:00' + signal: code2llm_smell_god_function + timestamp: '2026-09-18T19:51:27.884743+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '140' - key: semcod/tagi#140 - url: https://github.com/semcod/tagi/issues/140 - updated_at: '2026-09-18T19:36:57.323254+00:00' - PLF-136: + id: '143' + key: semcod/tagi#143 + url: https://github.com/semcod/tagi/issues/143 + updated_at: '2026-09-18T19:51:27.884743+00:00' + PLF-139: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-18T19:41:42.348704+00:00' - description: ' + created_at: '2026-09-18T20:26:23.964964+00:00' + description: ' - code2llm reports `Shotgun Surgery: cmd` in `src/tagi/scanner/diff.py:6`. + code2llm reports `God Function: build_tag_distribution_section` in `src/tagi/utils/summary_helpers.py:71`. - Mutation of variable ''cmd'' spans 13 functions. Changing this logic requires - work in many places. + Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, + mutations=9. Make the smallest refactor that removes the smell and run local tests.' @@ -2366,59 +2362,61 @@ sprint: executor: kind: human mode: interactive - external_id: '141' + external_id: '144' files: - - src/tagi/scanner/diff.py + - src/tagi/utils/summary_helpers.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: cmd` in `src/tagi/scanner/diff.py:6`. + message: 'code2llm reports `God Function: build_tag_distribution_section` + in `src/tagi/utils/summary_helpers.py:71`. - Mutation of variable ''cmd'' spans 13 functions. Changing this logic requires - work in many places. + Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, + mutations=9. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-18T19:41:42.348704+00:00' - id: PLF-136 + timestamp: '2026-09-18T20:26:23.964964+00:00' + id: PLF-139 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: cmd` in `src/tagi/scanner/diff.py:6`. + prompt: 'code2llm reports `God Function: build_tag_distribution_section` in + `src/tagi/utils/summary_helpers.py:71`. - Mutation of variable ''cmd'' spans 13 functions. Changing this logic requires - work in many places. + Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, + mutations=9. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - god-function metadata: - deduplication_key: PLF-136 - name: 'Address code smell: Shotgun Surgery: cmd' + deduplication_key: PLF-139 + name: 'Address code smell: God Function: build_tag_distribution_section' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/scanner/diff.py:6:Shotgun - Surgery: cmd' + dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/summary_helpers.py:71:God + Function: build_tag_distribution_section' evidence: artifact: mtime_ns: 1789760212841277131 @@ -2426,10 +2424,10 @@ sprint: sha256: e779a23e78575a5ca1103e1494c9f5b9bf0ac7bdcb3ffbbab82e37914fa8de0a size_bytes: 10336 files: - - mtime_ns: 1779802548044288725 - path: src/tagi/scanner/diff.py - sha256: 5c96c6b90833c3d6205e40b53b402d2b1eca555c135ff8bbd9cd94f8931716f2 - size_bytes: 708 + - mtime_ns: 1789760157304512513 + path: src/tagi/utils/summary_helpers.py + sha256: 5b80ca05e1202f10e13c9873597a0a11ddf86af9b7cdcb2a9bb2dfb60c233e6a + size_bytes: 3117 kind: code2llm_discovery planfile_tickets: mtime_ns: 1789760212873891603 @@ -2443,38 +2441,38 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: cmd` in `src/tagi/scanner/diff.py:6`. + input: 'code2llm reports `God Function: build_tag_distribution_section` + in `src/tagi/utils/summary_helpers.py:71`. - Mutation of variable ''cmd'' spans 13 functions. Changing this logic requires - work in many places. + Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, + mutations=9. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-18T19:41:42.348704+00:00' + signal: code2llm_smell_god_function + timestamp: '2026-09-18T20:26:23.964964+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '141' - key: semcod/tagi#141 - url: https://github.com/semcod/tagi/issues/141 - updated_at: '2026-09-18T19:41:42.348704+00:00' - PLF-137: + id: '144' + key: semcod/tagi#144 + url: https://github.com/semcod/tagi/issues/144 + updated_at: '2026-09-18T20:26:23.964964+00:00' + PLF-140: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-18T19:46:39.220367+00:00' - description: ' + created_at: '2026-09-18T20:31:21.515076+00:00' + description: ' - code2llm reports `Shotgun Surgery: logger` in `src/tagi/utils/logger.py:9`. + code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - Mutation of variable ''logger'' spans 5 functions. Changing this logic requires - work in many places. + Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. Make the smallest refactor that removes the smell and run local tests.' @@ -2486,59 +2484,57 @@ sprint: executor: kind: human mode: interactive - external_id: '142' + external_id: '145' files: - - src/tagi/utils/logger.py + - src/tagi/utils/inspect_helpers.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: logger` in `src/tagi/utils/logger.py:9`. + message: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - Mutation of variable ''logger'' spans 5 functions. Changing this logic requires - work in many places. + Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-18T19:46:39.220367+00:00' - id: PLF-137 + timestamp: '2026-09-18T20:31:21.515076+00:00' + id: PLF-140 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: logger` in `src/tagi/utils/logger.py:9`. + prompt: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - Mutation of variable ''logger'' spans 5 functions. Changing this logic requires - work in many places. + Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - god-function metadata: - deduplication_key: PLF-137 - name: 'Address code smell: Shotgun Surgery: logger' + deduplication_key: PLF-140 + name: 'Address code smell: God Function: display_statistics_table' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/utils/logger.py:9:Shotgun - Surgery: logger' + dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/inspect_helpers.py:109:God + Function: display_statistics_table' evidence: artifact: mtime_ns: 1789760212841277131 @@ -2546,10 +2542,10 @@ sprint: sha256: e779a23e78575a5ca1103e1494c9f5b9bf0ac7bdcb3ffbbab82e37914fa8de0a size_bytes: 10336 files: - - mtime_ns: 1779809465287675064 - path: src/tagi/utils/logger.py - sha256: 25d7171aee4d351bc65d315acfa6d09d6e91491346c2ac3cca945577d7397c89 - size_bytes: 1747 + - mtime_ns: 1789760157304512513 + path: src/tagi/utils/inspect_helpers.py + sha256: 1c596a23769394791c6155c0d18ffff189732a3df1916a648adcfab4b50d7606 + size_bytes: 3639 kind: code2llm_discovery planfile_tickets: mtime_ns: 1789760212873891603 @@ -2563,37 +2559,37 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: logger` in `src/tagi/utils/logger.py:9`. + input: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - Mutation of variable ''logger'' spans 5 functions. Changing this logic - requires work in many places. + Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-18T19:46:39.220367+00:00' + signal: code2llm_smell_god_function + timestamp: '2026-09-18T20:31:21.515076+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '142' - key: semcod/tagi#142 - url: https://github.com/semcod/tagi/issues/142 - updated_at: '2026-09-18T19:46:39.220367+00:00' - PLF-138: + id: '145' + key: semcod/tagi#145 + url: https://github.com/semcod/tagi/issues/145 + updated_at: '2026-09-18T20:31:21.515076+00:00' + PLF-141: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-18T19:51:27.884743+00:00' - description: ' + created_at: '2026-09-18T20:46:53.090400+00:00' + description: ' - code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. + code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. + Mutation of variable ''result'' spans 24 functions. Changing this logic requires + work in many places. Make the smallest refactor that removes the smell and run local tests.' @@ -2605,74 +2601,76 @@ sprint: executor: kind: human mode: interactive - external_id: '143' + external_id: '147' files: - - src/tagi/utils/summary_helpers.py + - src/tagi/scanner/diff.py history: - action: created - message: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. + message: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. + Mutation of variable ''result'' spans 24 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-18T19:51:27.884743+00:00' - id: PLF-138 + timestamp: '2026-09-18T20:46:53.090400+00:00' + id: PLF-141 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. + prompt: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. + Mutation of variable ''result'' spans 24 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: - - priority-normal - planfile - managed - koru - nl-task - llm-ready + - priority-high + - 'priority: high' - code2llm - - 'priority: normal' - code-smell - - god-function + - shotgun-surgery metadata: - deduplication_key: PLF-138 - name: 'Address code smell: God Function: build_statistics_section' + deduplication_key: PLF-141 + name: 'Address code smell: Shotgun Surgery: result' outputs: artifacts: [] notes: [] - priority: normal + priority: high source: context: - dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/summary_helpers.py:31:God - Function: build_statistics_section' + dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/scanner/diff.py:20:Shotgun + Surgery: result' evidence: artifact: - mtime_ns: 1789760212841277131 + mtime_ns: 1789764409471628814 path: project/analysis.toon.yaml - sha256: e779a23e78575a5ca1103e1494c9f5b9bf0ac7bdcb3ffbbab82e37914fa8de0a - size_bytes: 10336 + sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 + size_bytes: 10424 files: - - mtime_ns: 1789760157304512513 - path: src/tagi/utils/summary_helpers.py - sha256: 5b80ca05e1202f10e13c9873597a0a11ddf86af9b7cdcb2a9bb2dfb60c233e6a - size_bytes: 3117 + - mtime_ns: 1779802548044288725 + path: src/tagi/scanner/diff.py + sha256: 5c96c6b90833c3d6205e40b53b402d2b1eca555c135ff8bbd9cd94f8931716f2 + size_bytes: 708 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789760212873891603 + mtime_ns: 1789764409534879854 path: project/planfile-tickets.yaml - sha256: d0c2d6eb3eb46612e13fa7d7f524e92e895a3f31556b19210c5499cec6308586 - size_bytes: 22328 + sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a + size_bytes: 16701 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -2680,37 +2678,39 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `God Function: build_statistics_section` in `src/tagi/utils/summary_helpers.py:31`. + input: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - Function ''build_statistics_section'' is oversized: CC=2, fan-out=6, mutations=7. + Mutation of variable ''result'' spans 24 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_god_function - timestamp: '2026-09-18T19:51:27.884743+00:00' + signal: code2llm_smell_shotgun_surgery + timestamp: '2026-09-18T20:46:53.090400+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '143' - key: semcod/tagi#143 - url: https://github.com/semcod/tagi/issues/143 - updated_at: '2026-09-18T19:51:27.884743+00:00' - PLF-139: + id: '147' + key: semcod/tagi#147 + url: https://github.com/semcod/tagi/issues/147 + updated_at: '2026-09-18T20:46:53.090400+00:00' + PLF-142: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-18T20:26:23.964964+00:00' - description: ' + created_at: '2026-09-18T20:51:58.051382+00:00' + description: ' - code2llm reports `God Function: build_tag_distribution_section` in `src/tagi/utils/summary_helpers.py:71`. + code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, - mutations=9. + Arguments (repo_path, body, title) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' @@ -2722,34 +2722,34 @@ sprint: executor: kind: human mode: interactive - external_id: '144' + external_id: '148' files: - - src/tagi/utils/summary_helpers.py + - src/tagi/cli/provider_commands.py history: - action: created - message: 'code2llm reports `God Function: build_tag_distribution_section` - in `src/tagi/utils/summary_helpers.py:71`. + message: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, - mutations=9. + Arguments (repo_path, body, title) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-18T20:26:23.964964+00:00' - id: PLF-139 + timestamp: '2026-09-18T20:51:58.051382+00:00' + id: PLF-142 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `God Function: build_tag_distribution_section` in - `src/tagi/utils/summary_helpers.py:71`. + prompt: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, - mutations=9. + Arguments (repo_path, body, title) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' @@ -2765,730 +2765,10 @@ sprint: - code2llm - 'priority: normal' - code-smell - - god-function + - data-clump metadata: - deduplication_key: PLF-139 - name: 'Address code smell: God Function: build_tag_distribution_section' - outputs: - artifacts: [] - notes: [] - priority: normal - source: - context: - dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/summary_helpers.py:71:God - Function: build_tag_distribution_section' - evidence: - artifact: - mtime_ns: 1789760212841277131 - path: project/analysis.toon.yaml - sha256: e779a23e78575a5ca1103e1494c9f5b9bf0ac7bdcb3ffbbab82e37914fa8de0a - size_bytes: 10336 - files: - - mtime_ns: 1789760157304512513 - path: src/tagi/utils/summary_helpers.py - sha256: 5b80ca05e1202f10e13c9873597a0a11ddf86af9b7cdcb2a9bb2dfb60c233e6a - size_bytes: 3117 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789760212873891603 - path: project/planfile-tickets.yaml - sha256: d0c2d6eb3eb46612e13fa7d7f524e92e895a3f31556b19210c5499cec6308586 - size_bytes: 22328 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `God Function: build_tag_distribution_section` - in `src/tagi/utils/summary_helpers.py:71`. - - - Function ''build_tag_distribution_section'' is oversized: CC=5, fan-out=6, - mutations=9. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_god_function - timestamp: '2026-09-18T20:26:23.964964+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '144' - key: semcod/tagi#144 - url: https://github.com/semcod/tagi/issues/144 - updated_at: '2026-09-18T20:26:23.964964+00:00' - PLF-140: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T20:31:21.515076+00:00' - description: ' - - code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - - - Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '145' - files: - - src/tagi/utils/inspect_helpers.py - history: - - action: created - message: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - - - Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T20:31:21.515076+00:00' - id: PLF-140 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - - - Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - priority-normal - - planfile - - managed - - koru - - nl-task - - llm-ready - - code2llm - - 'priority: normal' - - code-smell - - god-function - metadata: - deduplication_key: PLF-140 - name: 'Address code smell: God Function: display_statistics_table' - outputs: - artifacts: [] - notes: [] - priority: normal - source: - context: - dedupe_key: 'code2llm:smell:god_function:src/tagi/utils/inspect_helpers.py:109:God - Function: display_statistics_table' - evidence: - artifact: - mtime_ns: 1789760212841277131 - path: project/analysis.toon.yaml - sha256: e779a23e78575a5ca1103e1494c9f5b9bf0ac7bdcb3ffbbab82e37914fa8de0a - size_bytes: 10336 - files: - - mtime_ns: 1789760157304512513 - path: src/tagi/utils/inspect_helpers.py - sha256: 1c596a23769394791c6155c0d18ffff189732a3df1916a648adcfab4b50d7606 - size_bytes: 3639 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789760212873891603 - path: project/planfile-tickets.yaml - sha256: d0c2d6eb3eb46612e13fa7d7f524e92e895a3f31556b19210c5499cec6308586 - size_bytes: 22328 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `God Function: display_statistics_table` in `src/tagi/utils/inspect_helpers.py:109`. - - - Function ''display_statistics_table'' is oversized: CC=1, fan-out=7, mutations=10. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_god_function - timestamp: '2026-09-18T20:31:21.515076+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '145' - key: semcod/tagi#145 - url: https://github.com/semcod/tagi/issues/145 - updated_at: '2026-09-18T20:31:21.515076+00:00' - PLF-141: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T20:46:53.090400+00:00' - description: ' - - code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - - - Mutation of variable ''result'' spans 24 functions. Changing this logic requires - work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '147' - files: - - src/tagi/scanner/diff.py - history: - - action: created - message: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - - - Mutation of variable ''result'' spans 24 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T20:46:53.090400+00:00' - id: PLF-141 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - - - Mutation of variable ''result'' spans 24 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - planfile - - managed - - koru - - nl-task - - llm-ready - - priority-high - - 'priority: high' - - code2llm - - code-smell - - shotgun-surgery - metadata: - deduplication_key: PLF-141 - name: 'Address code smell: Shotgun Surgery: result' - outputs: - artifacts: [] - notes: [] - priority: high - source: - context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/scanner/diff.py:20:Shotgun - Surgery: result' - evidence: - artifact: - mtime_ns: 1789764409471628814 - path: project/analysis.toon.yaml - sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 - size_bytes: 10424 - files: - - mtime_ns: 1779802548044288725 - path: src/tagi/scanner/diff.py - sha256: 5c96c6b90833c3d6205e40b53b402d2b1eca555c135ff8bbd9cd94f8931716f2 - size_bytes: 708 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789764409534879854 - path: project/planfile-tickets.yaml - sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a - size_bytes: 16701 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/diff.py:20`. - - - Mutation of variable ''result'' spans 24 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-18T20:46:53.090400+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '147' - key: semcod/tagi#147 - url: https://github.com/semcod/tagi/issues/147 - updated_at: '2026-09-18T20:46:53.090400+00:00' - PLF-142: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T20:51:58.051382+00:00' - description: ' - - code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (repo_path, body, title) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '148' - files: - - src/tagi/cli/provider_commands.py - history: - - action: created - message: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (repo_path, body, title) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T20:51:58.051382+00:00' - id: PLF-142 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (repo_path, body, title) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - priority-normal - - planfile - - managed - - koru - - nl-task - - llm-ready - - code2llm - - 'priority: normal' - - code-smell - - data-clump - metadata: - deduplication_key: PLF-142 - name: 'Address code smell: Data Clump: repo_path, body, title' - outputs: - artifacts: [] - notes: [] - priority: normal - source: - context: - dedupe_key: 'code2llm:smell:data_clump:src/tagi/cli/provider_commands.py:34:Data - Clump: repo_path, body, title' - evidence: - artifact: - mtime_ns: 1789764409471628814 - path: project/analysis.toon.yaml - sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 - size_bytes: 10424 - files: - - mtime_ns: 1789739346063914074 - path: src/tagi/cli/provider_commands.py - sha256: 68ce18c77819dae347a71d285994bba864fa304bce74de2420ca81f96c3f8225 - size_bytes: 2695 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789764409534879854 - path: project/planfile-tickets.yaml - sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a - size_bytes: 16701 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (repo_path, body, title) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_data_clump - timestamp: '2026-09-18T20:51:58.051382+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '148' - key: semcod/tagi#148 - url: https://github.com/semcod/tagi/issues/148 - updated_at: '2026-09-18T20:51:58.051382+00:00' - PLF-143: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T21:27:31.437891+00:00' - description: ' - - code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - - - Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '149' - files: - - src/tagi/planner/grouper.py - history: - - action: created - message: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - - - Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T21:27:31.437891+00:00' - id: PLF-143 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - - - Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - priority-normal - - planfile - - managed - - koru - - nl-task - - llm-ready - - code2llm - - 'priority: normal' - - code-smell - - god-function - metadata: - deduplication_key: PLF-143 - name: 'Address code smell: God Function: group_changes' - outputs: - artifacts: [] - notes: [] - priority: normal - source: - context: - dedupe_key: 'code2llm:smell:god_function:src/tagi/planner/grouper.py:10:God - Function: group_changes' - evidence: - artifact: - mtime_ns: 1789764409471628814 - path: project/analysis.toon.yaml - sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 - size_bytes: 10424 - files: - - mtime_ns: 1789760157304512513 - path: src/tagi/planner/grouper.py - sha256: 4f19a41a6d0fb1cc5e82e8210e9a0087aab90c22cb5b01a3879a9aff253b83f0 - size_bytes: 2197 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789764409534879854 - path: project/planfile-tickets.yaml - sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a - size_bytes: 16701 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - - - Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_god_function - timestamp: '2026-09-18T21:27:31.437891+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '149' - key: semcod/tagi#149 - url: https://github.com/semcod/tagi/issues/149 - updated_at: '2026-09-18T21:27:31.437891+00:00' - PLF-144: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T21:45:19.766961+00:00' - description: ' - - code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/inspect_helpers.py:96`. - - - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '151' - files: - - src/tagi/utils/inspect_helpers.py - history: - - action: created - message: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/inspect_helpers.py:96`. - - - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T21:45:19.766961+00:00' - id: PLF-144 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/inspect_helpers.py:96`. - - - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - planfile - - managed - - koru - - nl-task - - llm-ready - - priority-high - - 'priority: high' - - code2llm - - code-smell - - shotgun-surgery - metadata: - deduplication_key: PLF-144 - name: 'Address code smell: Shotgun Surgery: total_lines' - outputs: - artifacts: [] - notes: [] - priority: high - source: - context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/utils/inspect_helpers.py:96:Shotgun - Surgery: total_lines' - evidence: - artifact: - mtime_ns: 1789767907486023009 - path: project/analysis.toon.yaml - sha256: bffe51d44d6fb6464a866f3f92775ba60121d5c8ee5912e7e28815233ae3b49c - size_bytes: 10335 - files: - - mtime_ns: 1789760157304512513 - path: src/tagi/utils/inspect_helpers.py - sha256: 1c596a23769394791c6155c0d18ffff189732a3df1916a648adcfab4b50d7606 - size_bytes: 3639 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789767907544471268 - path: project/planfile-tickets.yaml - sha256: a1a17bb7fff1116657c2c5c8dc0925997c5d311418d5770edcae36e65433c9b5 - size_bytes: 16073 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/inspect_helpers.py:96`. - - - Mutation of variable ''total_lines'' spans 7 functions. Changing this - logic requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-18T21:45:19.766961+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '151' - key: semcod/tagi#151 - url: https://github.com/semcod/tagi/issues/151 - updated_at: '2026-09-18T21:45:19.766961+00:00' - PLF-145: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-18T21:51:29.650993+00:00' - description: ' - - code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (body, title, repo_path) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '152' - files: - - src/tagi/cli/provider_commands.py - history: - - action: created - message: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (body, title, repo_path) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-18T21:51:29.650993+00:00' - id: PLF-145 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - - - Arguments (body, title, repo_path) are used together in multiple functions: - src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, - src.tagi.cli.provider_commands.create_mr. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - priority-normal - - planfile - - managed - - koru - - nl-task - - llm-ready - - code2llm - - 'priority: normal' - - code-smell - - data-clump - metadata: - deduplication_key: PLF-145 - name: 'Address code smell: Data Clump: body, title, repo_path' + deduplication_key: PLF-142 + name: 'Address code smell: Data Clump: repo_path, body, title' outputs: artifacts: [] notes: [] @@ -3496,13 +2776,13 @@ sprint: source: context: dedupe_key: 'code2llm:smell:data_clump:src/tagi/cli/provider_commands.py:34:Data - Clump: body, title, repo_path' + Clump: repo_path, body, title' evidence: artifact: - mtime_ns: 1789767907486023009 + mtime_ns: 1789764409471628814 path: project/analysis.toon.yaml - sha256: bffe51d44d6fb6464a866f3f92775ba60121d5c8ee5912e7e28815233ae3b49c - size_bytes: 10335 + sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 + size_bytes: 10424 files: - mtime_ns: 1789739346063914074 path: src/tagi/cli/provider_commands.py @@ -3510,10 +2790,10 @@ sprint: size_bytes: 2695 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789767907544471268 + mtime_ns: 1789764409534879854 path: project/planfile-tickets.yaml - sha256: a1a17bb7fff1116657c2c5c8dc0925997c5d311418d5770edcae36e65433c9b5 - size_bytes: 16073 + sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a + size_bytes: 16701 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -3521,159 +2801,38 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. + input: 'code2llm reports `Data Clump: repo_path, body, title` in `src/tagi/cli/provider_commands.py:34`. - Arguments (body, title, repo_path) are used together in multiple functions: + Arguments (repo_path, body, title) are used together in multiple functions: src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' signal: code2llm_smell_data_clump - timestamp: '2026-09-18T21:51:29.650993+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '152' - key: semcod/tagi#152 - url: https://github.com/semcod/tagi/issues/152 - updated_at: '2026-09-18T21:51:29.650993+00:00' - PLF-146: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-19T06:26:13.380402+00:00' - description: ' - - code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '153' - files: - - src/tagi/heuristics/metrics.py - history: - - action: created - message: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-19T06:26:13.380402+00:00' - id: PLF-146 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - planfile - - managed - - koru - - nl-task - - llm-ready - - priority-high - - 'priority: high' - - code2llm - - code-smell - - shotgun-surgery - metadata: - deduplication_key: PLF-146 - name: 'Address code smell: Shotgun Surgery: path_lower' - outputs: - artifacts: [] - notes: [] - priority: high - source: - context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/heuristics/metrics.py:46:Shotgun - Surgery: path_lower' - evidence: - artifact: - mtime_ns: 1789799169500661533 - path: project/analysis.toon.yaml - sha256: e121c107d051daf013a3c36bbcbc8717b86b66089c73a3586f38da06dbdec891 - size_bytes: 10356 - files: - - mtime_ns: 1779811310790143885 - path: src/tagi/heuristics/metrics.py - sha256: dcd2cc0255c4f2ee3eee8aaae72af3e54f0aa6a78598d290d61eb44299401b2d - size_bytes: 6521 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789799169537365843 - path: project/planfile-tickets.yaml - sha256: 1d4adc5d27067e26cec142ccc46490afbb9b85cb5d197c470f6353698b37aceb - size_bytes: 17914 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T06:26:13.380402+00:00' + timestamp: '2026-09-18T20:51:58.051382+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '153' - key: semcod/tagi#153 - url: https://github.com/semcod/tagi/issues/153 - updated_at: '2026-09-19T06:26:13.380402+00:00' - PLF-147: + id: '148' + key: semcod/tagi#148 + url: https://github.com/semcod/tagi/issues/148 + updated_at: '2026-09-18T20:51:58.051382+00:00' + PLF-143: assignee: null backend: github blocked_by: [] - blocks: [] - created_at: '2026-09-19T06:31:54.694978+00:00' - description: ' + blocks: [] + created_at: '2026-09-18T21:27:31.437891+00:00' + description: ' - code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. + code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - Mutation of variable ''tags'' spans 6 functions. Changing this logic requires - work in many places. + Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. Make the smallest refactor that removes the smell and run local tests.' @@ -3685,76 +2844,74 @@ sprint: executor: kind: human mode: interactive - external_id: '154' + external_id: '149' files: - - src/tagi/composer/formats.py + - src/tagi/planner/grouper.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. + message: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - Mutation of variable ''tags'' spans 6 functions. Changing this logic requires - work in many places. + Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-19T06:31:54.694978+00:00' - id: PLF-147 + timestamp: '2026-09-18T21:27:31.437891+00:00' + id: PLF-143 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. + prompt: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - Mutation of variable ''tags'' spans 6 functions. Changing this logic requires - work in many places. + Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - god-function metadata: - deduplication_key: PLF-147 - name: 'Address code smell: Shotgun Surgery: tags' + deduplication_key: PLF-143 + name: 'Address code smell: God Function: group_changes' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/composer/formats.py:16:Shotgun - Surgery: tags' + dedupe_key: 'code2llm:smell:god_function:src/tagi/planner/grouper.py:10:God + Function: group_changes' evidence: artifact: - mtime_ns: 1789799169500661533 + mtime_ns: 1789764409471628814 path: project/analysis.toon.yaml - sha256: e121c107d051daf013a3c36bbcbc8717b86b66089c73a3586f38da06dbdec891 - size_bytes: 10356 + sha256: 8272c84ad525516fbd4040cd83b4fb110a3f4e91aa510378427c65686d9f3018 + size_bytes: 10424 files: - - mtime_ns: 1789764358606193196 - path: src/tagi/composer/formats.py - sha256: f83369fc3a57d03450699627061999b0e07c463e547289218fda64626fb0e6c0 - size_bytes: 3495 + - mtime_ns: 1789760157304512513 + path: src/tagi/planner/grouper.py + sha256: 4f19a41a6d0fb1cc5e82e8210e9a0087aab90c22cb5b01a3879a9aff253b83f0 + size_bytes: 2197 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789799169537365843 + mtime_ns: 1789764409534879854 path: project/planfile-tickets.yaml - sha256: 1d4adc5d27067e26cec142ccc46490afbb9b85cb5d197c470f6353698b37aceb - size_bytes: 17914 + sha256: e229a798269d410a9ccbb63568a783f63de2465f87ad7c4d3acd2a5c0b1ec43a + size_bytes: 16701 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -3762,38 +2919,38 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. + input: 'code2llm reports `God Function: group_changes` in `src/tagi/planner/grouper.py:10`. - Mutation of variable ''tags'' spans 6 functions. Changing this logic requires - work in many places. + Function ''group_changes'' is oversized: CC=5, fan-out=9, mutations=8. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T06:31:54.694978+00:00' + signal: code2llm_smell_god_function + timestamp: '2026-09-18T21:27:31.437891+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '154' - key: semcod/tagi#154 - url: https://github.com/semcod/tagi/issues/154 - updated_at: '2026-09-19T06:31:54.694978+00:00' - PLF-148: + id: '149' + key: semcod/tagi#149 + url: https://github.com/semcod/tagi/issues/149 + updated_at: '2026-09-18T21:27:31.437891+00:00' + PLF-145: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-19T07:27:50.494870+00:00' - description: ' + created_at: '2026-09-18T21:51:29.650993+00:00' + description: ' - code2llm reports `Shotgun Surgery: result` in `src/tagi/analyzer/dependency_graph.py:63`. + code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - Mutation of variable ''result'' spans 21 functions. Changing this logic requires - work in many places. + Arguments (body, title, repo_path) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' @@ -3805,76 +2962,78 @@ sprint: executor: kind: human mode: interactive - external_id: '156' + external_id: '152' files: - - src/tagi/analyzer/dependency_graph.py + - src/tagi/cli/provider_commands.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/analyzer/dependency_graph.py:63`. + message: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Arguments (body, title, repo_path) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-19T07:27:50.494870+00:00' - id: PLF-148 + timestamp: '2026-09-18T21:51:29.650993+00:00' + id: PLF-145 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/analyzer/dependency_graph.py:63`. + prompt: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Arguments (body, title, repo_path) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - data-clump metadata: - deduplication_key: PLF-148 - name: 'Address code smell: Shotgun Surgery: result' + deduplication_key: PLF-145 + name: 'Address code smell: Data Clump: body, title, repo_path' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/analyzer/dependency_graph.py:63:Shotgun - Surgery: result' + dedupe_key: 'code2llm:smell:data_clump:src/tagi/cli/provider_commands.py:34:Data + Clump: body, title, repo_path' evidence: artifact: - mtime_ns: 1789802857834310989 + mtime_ns: 1789767907486023009 path: project/analysis.toon.yaml - sha256: 44a5f094bf6499c25df8785d2a63dd595472e178a113134af703aac0487df20a - size_bytes: 10359 + sha256: bffe51d44d6fb6464a866f3f92775ba60121d5c8ee5912e7e28815233ae3b49c + size_bytes: 10335 files: - - mtime_ns: 1779810400712577609 - path: src/tagi/analyzer/dependency_graph.py - sha256: 56c60106b3e4d548089071146800fdcc6eddfdcb2b14c53bce8d7532487723bf - size_bytes: 5250 + - mtime_ns: 1789739346063914074 + path: src/tagi/cli/provider_commands.py + sha256: 68ce18c77819dae347a71d285994bba864fa304bce74de2420ca81f96c3f8225 + size_bytes: 2695 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789802857902888579 + mtime_ns: 1789767907544471268 path: project/planfile-tickets.yaml - sha256: c9019adbb39ec2478f27730553edf309610f894cd81234454f75961b809bd01d - size_bytes: 17909 + sha256: a1a17bb7fff1116657c2c5c8dc0925997c5d311418d5770edcae36e65433c9b5 + size_bytes: 16073 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -3882,37 +3041,39 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/analyzer/dependency_graph.py:63`. + input: 'code2llm reports `Data Clump: body, title, repo_path` in `src/tagi/cli/provider_commands.py:34`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Arguments (body, title, repo_path) are used together in multiple functions: + src.tagi.cli.provider_commands._pr_spec, src.tagi.cli.provider_commands.create_pr, + src.tagi.cli.provider_commands.create_mr. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T07:27:50.494870+00:00' + signal: code2llm_smell_data_clump + timestamp: '2026-09-18T21:51:29.650993+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '156' - key: semcod/tagi#156 - url: https://github.com/semcod/tagi/issues/156 - updated_at: '2026-09-19T07:27:50.494870+00:00' - PLF-149: + id: '152' + key: semcod/tagi#152 + url: https://github.com/semcod/tagi/issues/152 + updated_at: '2026-09-18T21:51:29.650993+00:00' + PLF-146: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-19T08:19:14.641869+00:00' - description: ' + created_at: '2026-09-19T06:26:13.380402+00:00' + description: ' - code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. + code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. + Mutation of variable ''path_lower'' spans 8 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' @@ -3924,74 +3085,76 @@ sprint: executor: kind: human mode: interactive - external_id: '158' + external_id: '153' files: - - src/tagi/cli/publishing_commands.py + - src/tagi/heuristics/metrics.py history: - action: created - message: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. + message: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. + Mutation of variable ''path_lower'' spans 8 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-19T08:19:14.641869+00:00' - id: PLF-149 + timestamp: '2026-09-19T06:26:13.380402+00:00' + id: PLF-146 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. + prompt: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. + Mutation of variable ''path_lower'' spans 8 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: - - priority-normal - planfile - managed - koru - nl-task - llm-ready + - priority-high + - 'priority: high' - code2llm - - 'priority: normal' - code-smell - - god-function + - shotgun-surgery metadata: - deduplication_key: PLF-149 - name: 'Address code smell: God Function: publish_command' + deduplication_key: PLF-146 + name: 'Address code smell: Shotgun Surgery: path_lower' outputs: artifacts: [] notes: [] - priority: normal + priority: high source: context: - dedupe_key: 'code2llm:smell:god_function:src/tagi/cli/publishing_commands.py:23:God - Function: publish_command' + dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/heuristics/metrics.py:46:Shotgun + Surgery: path_lower' evidence: artifact: - mtime_ns: 1789805947979310038 + mtime_ns: 1789799169500661533 path: project/analysis.toon.yaml - sha256: ff985a6d1df91bec113e0985da69266b7986b65971924ccd9f4fa7cbaea12c51 - size_bytes: 10323 + sha256: e121c107d051daf013a3c36bbcbc8717b86b66089c73a3586f38da06dbdec891 + size_bytes: 10356 files: - - mtime_ns: 1789740908490220674 - path: src/tagi/cli/publishing_commands.py - sha256: f11201cd601fcd3d52ba6ec5ff5b958f5663f79327593c81377c25c83574a07e - size_bytes: 5238 + - mtime_ns: 1779811310790143885 + path: src/tagi/heuristics/metrics.py + sha256: dcd2cc0255c4f2ee3eee8aaae72af3e54f0aa6a78598d290d61eb44299401b2d + size_bytes: 6521 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789805948011262070 + mtime_ns: 1789799169537365843 path: project/planfile-tickets.yaml - sha256: f8d503084189f0acc6b3277c59858501898b3b2ea7986cead8d6db848b15eb71 - size_bytes: 15477 + sha256: 1d4adc5d27067e26cec142ccc46490afbb9b85cb5d197c470f6353698b37aceb + size_bytes: 17914 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -3999,36 +3162,37 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. + input: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/metrics.py:46`. - Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. + Mutation of variable ''path_lower'' spans 8 functions. Changing this logic + requires work in many places. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_god_function - timestamp: '2026-09-19T08:19:14.641869+00:00' + signal: code2llm_smell_shotgun_surgery + timestamp: '2026-09-19T06:26:13.380402+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '158' - key: semcod/tagi#158 - url: https://github.com/semcod/tagi/issues/158 - updated_at: '2026-09-19T08:19:14.641869+00:00' - PLF-150: + id: '153' + key: semcod/tagi#153 + url: https://github.com/semcod/tagi/issues/153 + updated_at: '2026-09-19T06:26:13.380402+00:00' + PLF-147: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-19T08:40:27.418771+00:00' - description: ' + created_at: '2026-09-19T06:31:54.694978+00:00' + description: ' - code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/files.py:6`. + code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. - Mutation of variable ''result'' spans 21 functions. Changing this logic requires + Mutation of variable ''tags'' spans 6 functions. Changing this logic requires work in many places. @@ -4041,32 +3205,32 @@ sprint: executor: kind: human mode: interactive - external_id: '160' + external_id: '154' files: - - src/tagi/scanner/files.py + - src/tagi/composer/formats.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/files.py:6`. + message: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Mutation of variable ''tags'' spans 6 functions. Changing this logic requires + work in many places. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-19T08:40:27.418771+00:00' - id: PLF-150 + timestamp: '2026-09-19T06:31:54.694978+00:00' + id: PLF-147 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/files.py:6`. + prompt: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Mutation of variable ''tags'' spans 6 functions. Changing this logic requires + work in many places. Make the smallest refactor that removes the smell and run local tests.' @@ -4084,33 +3248,33 @@ sprint: - code-smell - shotgun-surgery metadata: - deduplication_key: PLF-150 - name: 'Address code smell: Shotgun Surgery: result' + deduplication_key: PLF-147 + name: 'Address code smell: Shotgun Surgery: tags' outputs: artifacts: [] notes: [] priority: high source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/scanner/files.py:6:Shotgun - Surgery: result' + dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/composer/formats.py:16:Shotgun + Surgery: tags' evidence: artifact: - mtime_ns: 1789807219128678462 + mtime_ns: 1789799169500661533 path: project/analysis.toon.yaml - sha256: a9502e24eae6c96a2813522009e1147c99df0b92b64fc43761c84a0421cc05d6 - size_bytes: 10335 + sha256: e121c107d051daf013a3c36bbcbc8717b86b66089c73a3586f38da06dbdec891 + size_bytes: 10356 files: - - mtime_ns: 1789767804220314391 - path: src/tagi/scanner/files.py - sha256: 1ce0abad16143ad14121aeb0637546495be090e81833345c8be620477c946379 - size_bytes: 926 + - mtime_ns: 1789764358606193196 + path: src/tagi/composer/formats.py + sha256: f83369fc3a57d03450699627061999b0e07c463e547289218fda64626fb0e6c0 + size_bytes: 3495 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789807219187356177 + mtime_ns: 1789799169537365843 path: project/planfile-tickets.yaml - sha256: 09f4267be8bbb0b623e89df1b4ad1ff583984dcab632ff1913d74642fffd254a - size_bytes: 16076 + sha256: 1d4adc5d27067e26cec142ccc46490afbb9b85cb5d197c470f6353698b37aceb + size_bytes: 17914 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -4118,38 +3282,37 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/files.py:6`. + input: 'code2llm reports `Shotgun Surgery: tags` in `src/tagi/composer/formats.py:16`. - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. + Mutation of variable ''tags'' spans 6 functions. Changing this logic requires + work in many places. Make the smallest refactor that removes the smell and run local tests.' signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T08:40:27.418771+00:00' + timestamp: '2026-09-19T06:31:54.694978+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '160' - key: semcod/tagi#160 - url: https://github.com/semcod/tagi/issues/160 - updated_at: '2026-09-19T08:40:27.418771+00:00' - PLF-151: + id: '154' + key: semcod/tagi#154 + url: https://github.com/semcod/tagi/issues/154 + updated_at: '2026-09-19T06:31:54.694978+00:00' + PLF-149: assignee: null backend: github blocked_by: [] blocks: [] - created_at: '2026-09-19T09:18:02.657696+00:00' - description: ' + created_at: '2026-09-19T08:19:14.641869+00:00' + description: ' - code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/send_helpers.py:8`. + code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. + Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. Make the smallest refactor that removes the smell and run local tests.' @@ -4161,76 +3324,74 @@ sprint: executor: kind: human mode: interactive - external_id: '161' + external_id: '158' files: - - src/tagi/utils/send_helpers.py + - src/tagi/cli/publishing_commands.py history: - action: created - message: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/send_helpers.py:8`. + message: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. + Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. Make the smallest refactor that removes the smell and run local tests.' source: koru task - timestamp: '2026-09-19T09:18:02.657696+00:00' - id: PLF-151 + timestamp: '2026-09-19T08:19:14.641869+00:00' + id: PLF-149 inputs: api_headers: {} api_method: GET api_timeout_seconds: 30.0 env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/send_helpers.py:8`. + prompt: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. - Mutation of variable ''total_lines'' spans 7 functions. Changing this logic - requires work in many places. + Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. Make the smallest refactor that removes the smell and run local tests.' integration: - github labels: + - priority-normal - planfile - managed - koru - nl-task - llm-ready - - priority-high - - 'priority: high' - code2llm + - 'priority: normal' - code-smell - - shotgun-surgery + - god-function metadata: - deduplication_key: PLF-151 - name: 'Address code smell: Shotgun Surgery: total_lines' + deduplication_key: PLF-149 + name: 'Address code smell: God Function: publish_command' outputs: artifacts: [] notes: [] - priority: high + priority: normal source: context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/utils/send_helpers.py:8:Shotgun - Surgery: total_lines' + dedupe_key: 'code2llm:smell:god_function:src/tagi/cli/publishing_commands.py:23:God + Function: publish_command' evidence: artifact: - mtime_ns: 1789807219128678462 + mtime_ns: 1789805947979310038 path: project/analysis.toon.yaml - sha256: a9502e24eae6c96a2813522009e1147c99df0b92b64fc43761c84a0421cc05d6 - size_bytes: 10335 + sha256: ff985a6d1df91bec113e0985da69266b7986b65971924ccd9f4fa7cbaea12c51 + size_bytes: 10323 files: - - mtime_ns: 1789807158230776613 - path: src/tagi/utils/send_helpers.py - sha256: 4e906f5b078ec49cd7523dfc93f794833dc887242454c6dca376f8af17483733 - size_bytes: 847 + - mtime_ns: 1789740908490220674 + path: src/tagi/cli/publishing_commands.py + sha256: f11201cd601fcd3d52ba6ec5ff5b958f5663f79327593c81377c25c83574a07e + size_bytes: 5238 kind: code2llm_discovery planfile_tickets: - mtime_ns: 1789807219187356177 + mtime_ns: 1789805948011262070 path: project/planfile-tickets.yaml - sha256: 09f4267be8bbb0b623e89df1b4ad1ff583984dcab632ff1913d74642fffd254a - size_bytes: 16076 + sha256: f8d503084189f0acc6b3277c59858501898b3b2ea7986cead8d6db848b15eb71 + size_bytes: 15477 regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source koru-project-discovery --planfile-sprint current --planfile-project @@ -4238,25 +3399,24 @@ sprint: schema: koru.ticket_evidence.v1 staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: total_lines` in `src/tagi/utils/send_helpers.py:8`. + input: 'code2llm reports `God Function: publish_command` in `src/tagi/cli/publishing_commands.py:23`. - Mutation of variable ''total_lines'' spans 7 functions. Changing this - logic requires work in many places. + Function ''publish_command'' is oversized: CC=11, fan-out=14, mutations=0. Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T09:18:02.657696+00:00' + signal: code2llm_smell_god_function + timestamp: '2026-09-19T08:19:14.641869+00:00' tool: koru-project-discovery sprint: current status: open sync: github: - id: '161' - key: semcod/tagi#161 - url: https://github.com/semcod/tagi/issues/161 - updated_at: '2026-09-19T09:18:02.657696+00:00' + id: '158' + key: semcod/tagi#158 + url: https://github.com/semcod/tagi/issues/158 + updated_at: '2026-09-19T08:19:14.641869+00:00' PLF-152: assignee: null backend: github @@ -4381,126 +3541,6 @@ sprint: key: semcod/tagi#162 url: https://github.com/semcod/tagi/issues/162 updated_at: '2026-09-19T09:23:37.677573+00:00' - PLF-153: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-19T09:36:55.436585+00:00' - description: ' - - code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/status.py:11`. - - - Mutation of variable ''result'' spans 21 functions. Changing this logic requires - work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '164' - files: - - src/tagi/scanner/status.py - history: - - action: created - message: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/status.py:11`. - - - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-19T09:36:55.436585+00:00' - id: PLF-153 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/status.py:11`. - - - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - planfile - - managed - - koru - - nl-task - - llm-ready - - priority-high - - 'priority: high' - - code2llm - - code-smell - - shotgun-surgery - metadata: - deduplication_key: PLF-153 - name: 'Address code smell: Shotgun Surgery: result' - outputs: - artifacts: [] - notes: [] - priority: high - source: - context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/scanner/status.py:11:Shotgun - Surgery: result' - evidence: - artifact: - mtime_ns: 1789810611546472552 - path: project/analysis.toon.yaml - sha256: 090d0a720b05f5191311983d22448bcf4753a2b60aa85c9ec6774f82c106a062 - size_bytes: 10253 - files: - - mtime_ns: 1789802617196896179 - path: src/tagi/scanner/status.py - sha256: 9b3ee07333cf0ae9ffcc6f3b02ead6d78b0c482d9994a0f4c84b528e9c944c29 - size_bytes: 1793 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789810611575073648 - path: project/planfile-tickets.yaml - sha256: 35e39935b4bf719d67de6de49341d2513dcd8a8946734749853b959382267ca0 - size_bytes: 16691 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: result` in `src/tagi/scanner/status.py:11`. - - - Mutation of variable ''result'' spans 21 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T09:36:55.436585+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '164' - key: semcod/tagi#164 - url: https://github.com/semcod/tagi/issues/164 - updated_at: '2026-09-19T09:36:55.436585+00:00' PLF-154: assignee: null backend: github @@ -4617,126 +3657,6 @@ sprint: key: semcod/tagi#166 url: https://github.com/semcod/tagi/issues/166 updated_at: '2026-09-19T10:22:37.567988+00:00' - PLF-155: - assignee: null - backend: github - blocked_by: [] - blocks: [] - created_at: '2026-09-19T10:49:16.509027+00:00' - description: ' - - code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/tags.py:57`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - execution: - attempt: 0 - max_attempts: 1 - queue: default - state: ready - executor: - kind: human - mode: interactive - external_id: '168' - files: - - src/tagi/heuristics/tags.py - history: - - action: created - message: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/tags.py:57`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - source: koru task - timestamp: '2026-09-19T10:49:16.509027+00:00' - id: PLF-155 - inputs: - api_headers: {} - api_method: GET - api_timeout_seconds: 30.0 - env_keys: [] - prompt: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/tags.py:57`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - integration: - - github - labels: - - planfile - - managed - - koru - - nl-task - - llm-ready - - priority-high - - 'priority: high' - - code2llm - - code-smell - - shotgun-surgery - metadata: - deduplication_key: PLF-155 - name: 'Address code smell: Shotgun Surgery: path_lower' - outputs: - artifacts: [] - notes: [] - priority: high - source: - context: - dedupe_key: 'code2llm:smell:shotgun_surgery:src/tagi/heuristics/tags.py:57:Shotgun - Surgery: path_lower' - evidence: - artifact: - mtime_ns: 1789814952782525610 - path: project/analysis.toon.yaml - sha256: 0b4667123d8ba68e72937f0d888d34497c85fbaa99ce8d7195d2bfaa19de1d9f - size_bytes: 10366 - files: - - mtime_ns: 1789814872390483855 - path: src/tagi/heuristics/tags.py - sha256: 83621bcdf280f42f072878df2f2475f25ec874bd8f7ecc8bcc5e04bb8e163174 - size_bytes: 3136 - kind: code2llm_discovery - planfile_tickets: - mtime_ns: 1789814952811053566 - path: project/planfile-tickets.yaml - sha256: 5ebd22cb45332ff8e61df65ac32e80d19ec57d2a54d226b6d4fd70230700cd67 - size_bytes: 15989 - regenerate_command: code2llm /home/tom/github/semcod/tagi -f all -o /home/tom/github/semcod/tagi/project - --no-chunk --exclude *.md --exclude plugins --planfile-apply --planfile-source - koru-project-discovery --planfile-sprint current --planfile-project - /home/tom/github/semcod/tagi --planfile-limit 20 - schema: koru.ticket_evidence.v1 - staleness_check: Regenerate artifacts and compare artifact.sha256 / files[].sha256 - before assuming this ticket is still current. - input: 'code2llm reports `Shotgun Surgery: path_lower` in `src/tagi/heuristics/tags.py:57`. - - - Mutation of variable ''path_lower'' spans 8 functions. Changing this logic - requires work in many places. - - - Make the smallest refactor that removes the smell and run local tests.' - signal: code2llm_smell_shotgun_surgery - timestamp: '2026-09-19T10:49:16.509027+00:00' - tool: koru-project-discovery - sprint: current - status: open - sync: - github: - id: '168' - key: semcod/tagi#168 - url: https://github.com/semcod/tagi/issues/168 - updated_at: '2026-09-19T10:49:16.509027+00:00' PLF-156: assignee: null backend: github diff --git a/src/tagi/analyzer/dependency_graph.py b/src/tagi/analyzer/dependency_graph.py index 2c1fcc6..adf1fd8 100644 --- a/src/tagi/analyzer/dependency_graph.py +++ b/src/tagi/analyzer/dependency_graph.py @@ -100,14 +100,14 @@ def levels(self) -> List[List[str]]: Returns: List of levels, each containing files that can be committed together """ - result: List[List[str]] = [] + commit_groups: List[List[str]] = [] while self.queue: level = self._drain_level() if level: - result.append(level) + commit_groups.append(level) - return result + return commit_groups def _drain_level(self) -> List[str]: """Pop one queue level and enqueue dependents that become unblocked. diff --git a/src/tagi/cli/provider_commands.py b/src/tagi/cli/provider_commands.py index 65a5c56..2ae8462 100644 --- a/src/tagi/cli/provider_commands.py +++ b/src/tagi/cli/provider_commands.py @@ -26,12 +26,11 @@ def detect_provider_command(repo_path: str = ".") -> Optional[str]: def _current_branch(repo_path: str) -> str: """Resolve the current git branch for the repository.""" - import subprocess - result = subprocess.run( + from tagi.utils.commands import run_command + return run_command( ["git", "rev-parse", "--abbrev-ref", "HEAD"], - cwd=repo_path, capture_output=True, text=True, check=False, - ) - return result.stdout.strip() or "main" + repo_path, + ).stdout.strip() or "main" def _pr_spec(spec: PrSpec, repo_path: str) -> PrSpec: diff --git a/src/tagi/composer/_tags.py b/src/tagi/composer/_tags.py index edf1813..cf4e1e8 100644 --- a/src/tagi/composer/_tags.py +++ b/src/tagi/composer/_tags.py @@ -19,11 +19,11 @@ def all_tag_values(changes: List[Change]) -> List[str]: def summary_tag(changes: List[Change]) -> str: """Choose a stable tag prefix for a commit spanning one or more changes.""" - tags = all_tags(changes) - if not tags: + unique_tags = all_tags(changes) + if not unique_tags: return "#small" - if len(tags) == 1: - return tags[0].value + if len(unique_tags) == 1: + return unique_tags[0].value return "#all" diff --git a/src/tagi/composer/formats.py b/src/tagi/composer/formats.py index eb7e96f..66f6b3e 100644 --- a/src/tagi/composer/formats.py +++ b/src/tagi/composer/formats.py @@ -45,8 +45,8 @@ def generate_conventional_message(changes: List[Change]) -> str: return "chore: empty commit" # Determine type from tags - tags = set(all_tags(changes)) - commit_type = _commit_type(tags) + tag_set = set(all_tags(changes)) + commit_type = _commit_type(tag_set) # Determine scope from file paths scope = infer_scope(changes) @@ -55,7 +55,7 @@ def generate_conventional_message(changes: List[Change]) -> str: description = _describe_changes(changes) # Add optional breaking change indicator - breaking = "!" if Tag.RISKY in tags else "" + breaking = "!" if Tag.RISKY in tag_set else "" if scope: return f"{commit_type}({scope}){breaking}: {description}" diff --git a/src/tagi/config.py b/src/tagi/config.py index 1f42711..efcbdb8 100644 --- a/src/tagi/config.py +++ b/src/tagi/config.py @@ -4,6 +4,8 @@ from pathlib import Path from typing import Dict, List, Optional +from tagi.utils.paths import path_matches + try: import tomli except ImportError: @@ -70,12 +72,10 @@ def _apply_sections(self, data): def get_tag_for_path(self, path: str) -> Optional[str]: """Get custom tag for a file path based on rules.""" - path_lower = path.lower() - for pattern, tag in self.custom_rules.items(): - if pattern.lower() in path_lower: + if path_matches(path, pattern): return tag - + return None def get_custom_tags_for_pattern(self, pattern: str) -> List[str]: @@ -88,14 +88,12 @@ def get_tag_color(self, tag: str) -> Optional[str]: def get_heuristics_for_path(self, path: str) -> List[str]: """Get custom heuristic tags for a file path.""" - path_lower = path.lower() - tags = [] - - for pattern, pattern_tags in self.custom_heuristics.items(): - if pattern.lower() in path_lower: - tags.extend(pattern_tags) - - return tags + return [ + pattern_tag + for pattern, pattern_tags in self.custom_heuristics.items() + if path_matches(path, pattern) + for pattern_tag in pattern_tags + ] def get_tags_for_path(self, path: str) -> List[str]: """Get all custom tags for a file path: rule tag first, then heuristic tags.""" @@ -112,13 +110,7 @@ def get_template(self, template_name: str) -> Optional[str]: def should_ignore(self, path: str) -> bool: """Check if a path should be ignored based on ignore patterns.""" - path_lower = path.lower() - - for pattern in self.ignore_patterns: - if pattern.lower() in path_lower: - return True - - return False + return any(path_matches(path, pattern) for pattern in self.ignore_patterns) def load_config(repo_path: str = ".") -> Config: diff --git a/src/tagi/executor/git.py b/src/tagi/executor/git.py index e6589f6..aa9324c 100644 --- a/src/tagi/executor/git.py +++ b/src/tagi/executor/git.py @@ -1,9 +1,10 @@ """Git executor module for running git commands.""" -import subprocess from subprocess import CompletedProcess from typing import List, Optional +from tagi.utils.commands import run_command + class GitExecutor: """Executor for git commands.""" @@ -13,40 +14,34 @@ def __init__(self, repo_path: str = "."): def _run_command(self, command: list[str]) -> CompletedProcess: """Run a command in the repository and return the result.""" - return subprocess.run( - command, - cwd=self.repo_path, - capture_output=True, - text=True, - check=False - ) + return run_command(command, self.repo_path) def add(self, files: List[str]) -> bool: """Stage files for commit.""" if not files: return False - result = self._run_command(["git", "add", *files]) - if result.returncode != 0: - raise RuntimeError(f"Failed to stage files: {result.stderr}") + staged = self._run_command(["git", "add", *files]) + if staged.returncode != 0: + raise RuntimeError(f"Failed to stage files: {staged.stderr}") return True def commit(self, message: str, allow_empty: bool = False) -> bool: """Commit staged changes.""" - result = self._run_command( + committed = self._run_command( ["git", "commit", "-m", message] + (["--allow-empty"] if allow_empty else []) ) - if result.returncode != 0: - raise RuntimeError(f"Failed to commit: {result.stderr}") + if committed.returncode != 0: + raise RuntimeError(f"Failed to commit: {committed.stderr}") return True def push(self, remote: str = "origin", branch: Optional[str] = None, force: bool = False) -> bool: """Push commits to remote.""" - result = self._run_command( + pushed = self._run_command( (["git", "push", remote, branch] if branch else ["git", "push"]) + (["--force"] if force else []) ) - if result.returncode != 0: - raise RuntimeError(f"Failed to push: {result.stderr}") + if pushed.returncode != 0: + raise RuntimeError(f"Failed to push: {pushed.stderr}") return True def status(self) -> str: @@ -55,16 +50,16 @@ def status(self) -> str: def get_current_branch(self) -> str: """Get the current branch name.""" - result = self._run_command(["git", "branch", "--show-current"]) - if result.returncode == 0: - return result.stdout.strip() + branch = self._run_command(["git", "branch", "--show-current"]) + if branch.returncode == 0: + return branch.stdout.strip() return "main" def get_remote_url(self, remote: str = "origin") -> Optional[str]: """Get the remote URL.""" - result = self._run_command(["git", "remote", "get-url", remote]) - if result.returncode == 0: - return result.stdout.strip() + url = self._run_command(["git", "remote", "get-url", remote]) + if url.returncode == 0: + return url.stdout.strip() return None def has_staged_changes(self) -> bool: diff --git a/src/tagi/heuristics/metrics.py b/src/tagi/heuristics/metrics.py index 7317540..37cbad3 100644 --- a/src/tagi/heuristics/metrics.py +++ b/src/tagi/heuristics/metrics.py @@ -3,6 +3,7 @@ import math from typing import List from tagi.models.change import Change, ChangeMetrics, ChangeType +from tagi.utils.paths import path_endswith, path_matches _COMPLEXITY_EXTENSION_WEIGHTS = ( @@ -32,18 +33,16 @@ def _extension_complexity_weight(path: str) -> float: """Return the complexity weight for a file path (first matching suffix wins).""" - path_lower = path.lower() for suffixes, weight in _COMPLEXITY_EXTENSION_WEIGHTS: - if path_lower.endswith(suffixes): + if path_endswith(path, suffixes): return weight return _DEFAULT_COMPLEXITY_EXTENSION_WEIGHT def _extension_impact_weight(path: str) -> float: """Return the impact weight for a file path (first matching suffix wins).""" - path_lower = path.lower() for suffixes, weight in _IMPACT_EXTENSION_WEIGHTS: - if path_lower.endswith(suffixes): + if path_endswith(path, suffixes): return weight return _DEFAULT_IMPACT_EXTENSION_WEIGHT @@ -134,14 +133,12 @@ def _calculate_stability(change: Change) -> float: def _calculate_test_impact(change: Change) -> float: """Calculate test coverage impact (0-1).""" - path_lower = change.path.lower() - # Test files have high impact on test coverage - if 'test' in path_lower or 'spec' in path_lower: + if path_matches(change.path, 'test') or path_matches(change.path, 'spec'): return 0.9 # Source files have moderate impact - if path_lower.endswith(('.py', '.js', '.ts')): + if path_endswith(change.path, ('.py', '.js', '.ts')): return 0.6 # Other files have low impact @@ -151,14 +148,12 @@ def _calculate_test_impact(change: Change) -> float: def _calculate_dependency_depth(change: Change) -> int: """Calculate dependency depth (simplified).""" # This is a simplified version - real implementation would parse imports - path_lower = change.path.lower() - - if path_lower.endswith('.py'): + if path_endswith(change.path, ('.py',)): # Python files typically have more dependencies return 3 - elif path_lower.endswith(('.js', '.ts', '.jsx', '.tsx')): + elif path_endswith(change.path, ('.js', '.ts', '.jsx', '.tsx')): return 2 - elif path_lower.endswith(('.json', '.yaml', '.yml')): + elif path_endswith(change.path, ('.json', '.yaml', '.yml')): return 1 else: return 0 diff --git a/src/tagi/heuristics/tags.py b/src/tagi/heuristics/tags.py index 9769653..f36b425 100644 --- a/src/tagi/heuristics/tags.py +++ b/src/tagi/heuristics/tags.py @@ -5,6 +5,7 @@ from tagi.config import load_config from tagi.models import Change, ChangeType, Tag from tagi.scanner.files import count_lines_changed +from tagi.utils.paths import path_matches from .scoring import calculate_risk_score from .metrics import calculate_metrics @@ -47,13 +48,13 @@ def _tag_change(change: Change, repo_path: str, custom_tags_for) -> None: def _custom_config_tags(custom_tags_for, path: str): """Convert configured custom tag names into valid Tag values.""" - tags = [] + valid_tags = [] for custom_tag in custom_tags_for(path): try: - tags.append(Tag(custom_tag)) + valid_tags.append(Tag(custom_tag)) except ValueError: pass # Invalid tag, skip - return tags + return valid_tags def _size_tags(lines_changed: int, has_other_tags: bool): @@ -68,8 +69,6 @@ def _size_tags(lines_changed: int, has_other_tags: bool): def apply_path_tags(change: Change, lines_changed: int) -> List[Tag]: """Apply path-based heuristic tags to a change.""" - path_lower = change.path.lower() - # Pattern mapping for tag detection tag_patterns = [ (['requirements', 'package.json', 'poetry.lock', 'pyproject.toml', 'cargo.toml', 'go.mod', 'yarn.lock', 'pnpm-lock.yaml', 'package-lock.json', 'gemfile', 'composer.json'], Tag.DEPS), @@ -85,5 +84,5 @@ def apply_path_tags(change: Change, lines_changed: int) -> List[Tag]: return [ tag for patterns, tag in tag_patterns - if any(pattern in path_lower for pattern in patterns) + if any(path_matches(change.path, pattern) for pattern in patterns) ] diff --git a/src/tagi/planner/branch_grouper.py b/src/tagi/planner/branch_grouper.py index c4c8e24..4e28d75 100644 --- a/src/tagi/planner/branch_grouper.py +++ b/src/tagi/planner/branch_grouper.py @@ -15,26 +15,24 @@ def group_by_branch(changes: List[Change], repo_path: str = ".") -> Dict[str, Li Dictionary mapping branch names to lists of changes """ from tagi.executor.git import GitExecutor - import subprocess - + from tagi.utils.commands import run_command + executor = GitExecutor(repo_path) current_branch = executor.get_current_branch() - + # Get branch history for each file branch_groups: Dict[str, List[Change]] = {} - + for change in changes: try: # Get the branch where the file was last modified - result = subprocess.run( + contains = run_command( ["git", "branch", "--contains", "HEAD", "--", change.path], - cwd=repo_path, - capture_output=True, - text=True + repo_path, ) - - if result.returncode == 0: - branches = result.stdout.strip().split('\n') + + if contains.returncode == 0: + branches = contains.stdout.strip().split('\n') # Clean up branch names (remove * prefix) branches = [b.strip().replace('*', '').strip() for b in branches if b.strip()] @@ -64,21 +62,16 @@ def get_branch_info(repo_path: str = ".") -> Dict[str, str]: Returns: Dictionary mapping branch names to their latest commit hashes """ - import subprocess - + from tagi.utils.commands import run_command + try: - result = subprocess.run( - ["git", "branch", "-a"], - cwd=repo_path, - capture_output=True, - text=True - ) - - if result.returncode != 0: + branch_listing = run_command(["git", "branch", "-a"], repo_path) + + if branch_listing.returncode != 0: return {} - + branches = {} - for line in result.stdout.strip().split('\n'): + for line in branch_listing.stdout.strip().split('\n'): branch = line.strip().replace('*', '').strip() if branch: branches[branch] = branch # Could be extended to include commit hash diff --git a/src/tagi/providers/base.py b/src/tagi/providers/base.py index e5784fc..c336b61 100644 --- a/src/tagi/providers/base.py +++ b/src/tagi/providers/base.py @@ -5,6 +5,8 @@ from dataclasses import dataclass, field from typing import List, Optional +from tagi.utils.commands import run_command + @dataclass class PrSpec: @@ -47,19 +49,13 @@ def detect_remote(self) -> bool: def _run_command(self, cmd: List[str]) -> subprocess.CompletedProcess: """Run a command and return the result.""" - return subprocess.run( - cmd, - cwd=self.repo_path, - capture_output=True, - text=True, - check=False - ) - + return run_command(cmd, self.repo_path) + def _get_git_remote_url(self) -> Optional[str]: """Get the git remote URL for the repository.""" - result = self._run_command(["git", "remote", "get-url", "origin"]) - if result.returncode == 0: - return result.stdout.strip() + remote = self._run_command(["git", "remote", "get-url", "origin"]) + if remote.returncode == 0: + return remote.stdout.strip() return None def _check_git_remote_for_provider(self, provider_name: str) -> bool: diff --git a/src/tagi/providers/github.py b/src/tagi/providers/github.py index bc6448b..038bfa5 100644 --- a/src/tagi/providers/github.py +++ b/src/tagi/providers/github.py @@ -14,19 +14,17 @@ class GitHubProvider(BaseProvider): def is_authenticated(self) -> bool: """Check if gh CLI is authenticated.""" - result = self._run_command(["gh", "auth", "status"]) - return is_authenticated_from_result(result) - + return is_authenticated_from_result(self._run_command(["gh", "auth", "status"])) + def get_auth_status(self) -> dict: """Get detailed authentication status.""" - result = self._run_command(["gh", "auth", "status"]) - return get_auth_status_from_result(result) - + return get_auth_status_from_result(self._run_command(["gh", "auth", "status"])) + def get_token(self) -> str: """Get the GitHub authentication token.""" - result = self._run_command(["gh", "auth", "token"]) - if result.returncode == 0: - return result.stdout.strip() + token = self._run_command(["gh", "auth", "token"]) + if token.returncode == 0: + return token.stdout.strip() return "" def create_pr(self, spec: PrSpec) -> str: diff --git a/src/tagi/providers/gitlab.py b/src/tagi/providers/gitlab.py index 8da582e..d82be9a 100644 --- a/src/tagi/providers/gitlab.py +++ b/src/tagi/providers/gitlab.py @@ -15,22 +15,20 @@ class GitLabProvider(BaseProvider): def is_authenticated(self) -> bool: """Check if glab CLI is authenticated.""" - result = self._run_command(["glab", "auth", "status"]) - return is_authenticated_from_result(result) - + return is_authenticated_from_result(self._run_command(["glab", "auth", "status"])) + def get_auth_status(self) -> dict: """Get detailed authentication status.""" - result = self._run_command(["glab", "auth", "status"]) - return get_auth_status_from_result(result) - + return get_auth_status_from_result(self._run_command(["glab", "auth", "status"])) + def get_configured_host(self) -> str: """Get the configured GitLab host.""" - result = self._run_command(["glab", "api", "/user"]) - if result.returncode == 0: + user = self._run_command(["glab", "api", "/user"]) + if user.returncode == 0: # Parse host from API response import json try: - data = json.loads(result.stdout) + data = json.loads(user.stdout) if "web_url" in data: from urllib.parse import urlparse return urlparse(data["web_url"]).netloc diff --git a/src/tagi/scanner/diff.py b/src/tagi/scanner/diff.py index 4978c4f..ee45180 100644 --- a/src/tagi/scanner/diff.py +++ b/src/tagi/scanner/diff.py @@ -1,29 +1,13 @@ """Diff module for getting git diffs.""" -import subprocess +from tagi.utils.commands import run_command def get_diff(file_path: str, repo_path: str = ".") -> str: """Get the diff for a specific file.""" - result = subprocess.run( - ["git", "diff", file_path], - cwd=repo_path, - capture_output=True, - text=True, - check=False - ) - - return result.stdout + return run_command(["git", "diff", file_path], repo_path).stdout def get_staged_diff(file_path: str, repo_path: str = ".") -> str: """Get the staged diff for a specific file.""" - result = subprocess.run( - ["git", "diff", "--cached", file_path], - cwd=repo_path, - capture_output=True, - text=True, - check=False - ) - - return result.stdout + return run_command(["git", "diff", "--cached", file_path], repo_path).stdout diff --git a/src/tagi/scanner/files.py b/src/tagi/scanner/files.py index 2086f89..bb476ca 100644 --- a/src/tagi/scanner/files.py +++ b/src/tagi/scanner/files.py @@ -2,23 +2,19 @@ import subprocess +from tagi.utils.commands import run_command + def count_lines_changed(file_path: str, repo_path: str = ".") -> int: """Count the number of lines changed in a file.""" try: - result = subprocess.run( - ["git", "diff", "--numstat", file_path], - cwd=repo_path, - capture_output=True, - text=True, - check=False - ) - - if result.returncode != 0 or not result.stdout.strip(): + numstat = run_command(["git", "diff", "--numstat", file_path], repo_path) + + if numstat.returncode != 0 or not numstat.stdout.strip(): return 0 - + # git diff --numstat output: additions deletions filename - parts = result.stdout.strip().split() + parts = numstat.stdout.strip().split() if len(parts) >= 2: additions = int(parts[0]) if parts[0] != '-' else 0 deletions = int(parts[1]) if parts[1] != '-' else 0 diff --git a/src/tagi/scanner/status.py b/src/tagi/scanner/status.py index 9991e91..2ef2180 100644 --- a/src/tagi/scanner/status.py +++ b/src/tagi/scanner/status.py @@ -1,33 +1,27 @@ """Status module for parsing git status.""" import os -import subprocess from typing import List from tagi.models import Change, ChangeType from tagi.config import load_config +from tagi.utils.commands import run_command def scan_repo(repo_path: str = ".") -> List[Change]: """Scan repository for uncommitted changes using git status --porcelain.""" if not os.path.exists(os.path.join(repo_path, ".git")): raise ValueError(f"Not a git repository: {repo_path}") - + should_ignore = load_config(repo_path).should_ignore - - result = subprocess.run( - ["git", "status", "--porcelain"], - cwd=repo_path, - capture_output=True, - text=True, - check=False - ) - - if result.returncode != 0: - raise RuntimeError(f"Failed to scan repository: {result.stderr}") - + + status = run_command(["git", "status", "--porcelain"], repo_path) + + if status.returncode != 0: + raise RuntimeError(f"Failed to scan repository: {status.stderr}") + changes = [] - for line in result.stdout.strip().split('\n'): + for line in status.stdout.strip().split('\n'): if not line: continue diff --git a/src/tagi/utils/commands.py b/src/tagi/utils/commands.py new file mode 100644 index 0000000..50f4635 --- /dev/null +++ b/src/tagi/utils/commands.py @@ -0,0 +1,20 @@ +"""Shared subprocess command execution. + +Single owner of the ``subprocess.run`` call pattern, extracted to remove +the ``result`` shotgun-surgery smell (PLF-141). Everything that shells out +goes through :func:`run_command` so execution behavior is defined once. +""" + +import subprocess +from typing import List + + +def run_command(cmd: List[str], cwd: str = ".") -> subprocess.CompletedProcess: + """Run a command in a directory and return the completed process.""" + return subprocess.run( + cmd, + cwd=cwd, + capture_output=True, + text=True, + check=False, + ) diff --git a/src/tagi/utils/detect_provider.py b/src/tagi/utils/detect_provider.py index bccf35e..6eb58cf 100644 --- a/src/tagi/utils/detect_provider.py +++ b/src/tagi/utils/detect_provider.py @@ -2,11 +2,11 @@ from typing import Optional from pathlib import Path -import subprocess from tagi.providers.base import BaseProvider from tagi.providers.github import GitHubProvider from tagi.providers.gitlab import GitLabProvider +from tagi.utils.commands import run_command def get_provider(repo_path: str = ".") -> Optional[BaseProvider]: @@ -36,19 +36,17 @@ def detect_git_provider(repo_path: str = ".") -> Optional[str]: 'github', 'gitlab', or None if unknown """ try: - result = subprocess.run( - ["git", "remote", "-v"], - cwd=repo_path, - capture_output=True, - text=True, - check=True - ) - output = result.stdout.lower() - + remotes = run_command(["git", "remote", "-v"], repo_path) + + if remotes.returncode != 0: + return None + + output = remotes.stdout.lower() + if "github.com" in output: return "github" elif "gitlab.com" in output: return "gitlab" return None - except (subprocess.CalledProcessError, FileNotFoundError): + except FileNotFoundError: return None diff --git a/src/tagi/utils/paths.py b/src/tagi/utils/paths.py new file mode 100644 index 0000000..7a080b6 --- /dev/null +++ b/src/tagi/utils/paths.py @@ -0,0 +1,24 @@ +"""Shared case-insensitive path matching. + +Single owner of the lowercased-path matching pattern, extracted to remove +the ``path_lower`` shotgun-surgery smell (PLF-146). Every path lookup goes +through :func:`path_key`, :func:`path_matches` or :func:`path_endswith` +so the normalization policy is defined once. +""" + +from typing import Tuple + + +def path_key(path: str) -> str: + """Return the canonical lowercase form of a path for matching.""" + return path.lower() + + +def path_matches(path: str, pattern: str) -> bool: + """Check whether a path contains a pattern, case-insensitively.""" + return pattern.lower() in path_key(path) + + +def path_endswith(path: str, suffixes: Tuple[str, ...]) -> bool: + """Check whether a path ends with any suffix, case-insensitively.""" + return path_key(path).endswith(suffixes)