Skip to content

function-length-check pre-commit hook blocks any commit to lifespan.py: cleanup_services (267 lines) and _init_graph_rag_service (68 lines) exceed the 65-line ceiling #16250

Closed

Description

@mrveiss

The local function-length-check pre-commit hook (autobot-infrastructure/shared/scripts/hooks/pre-commit-function-length) scans every staged .py file in full (no diff-scoping, no baseline/grandfather list, unlike scripts/python_file_size_known_large.py's file-size ratchet). Two pre-existing functions in autobot-backend/initialization/lifespan.py already exceed its 65-line ERROR threshold, and now block any local commit that stages this file at all, regardless of what the commit actually changes.

Discovered while implementing #16231 (Dev_new_gui, worktree issue-16231-pricing-install): a one-line addition to initialize_background_services (net zero line change to the file) could not be committed locally because git commit re-scans the whole file and reports:

ERROR autobot-backend/initialization/lifespan.py:1167
  Function '_init_graph_rag_service' has 68 body lines
  Threshold: >65 lines

ERROR autobot-backend/initialization/lifespan.py:2251
  Function 'cleanup_services' has 267 body lines
  Threshold: >65 lines

COMMIT BLOCKED: 2 function(s) exceed 65 lines

Neither function was touched by the #16231 change (confirmed via git diff hunks).

Notes:

  • cleanup_services grew to its current shape in bug(lifespan): shutdown handler joins its own thread, and its except swallows every later cleanup error #13585 (shutdown-teardown rewrite that guards each step independently — see its docstring). _init_graph_rag_service predates that.
  • CI's enforce-precommit.yml runs pre-commit diff-scoped (--from-ref HEAD^1 --to-ref HEAD^2) and treats hook findings as informational (::warning::), not blocking, for every hook except the one behavioural-gating hook (ssot-config-lib-guard). So this specific gap is local-only: it does not currently gate merges, but it does block a correctly-scoped local git commit on these two files for anyone who has pre-commit installed, indefinitely, until someone refactors code unrelated to their own change.

Fix options:

  1. Refactor cleanup_services (extract per-resource teardown helpers) and _init_graph_rag_service (extract the LlamaIndex construction block) under 65 body lines each, following the hook's own "Extract Method" guidance.
  2. Or give the local hook the same diff-scoping / baseline mechanism python_file_size_known_large.py has for file size, so a legacy function does not block an unrelated change to the same file.

Either closes the gap between "local pre-commit blocks" and "CI does not," which is itself worth resolving on its own (a required local gate that is silently advisory in CI is confusing and invites --no-verify).

Activity

  1. mrveiss commented on Sep 11, 2026

    @mrveiss
    OwnerAuthor

    This is an instance of #16191, not a separate defect. It's the same hook, function-length-check, and the same whole-file read. #16191's first acceptance criterion covers this case word for word: "A one-line change to a file containing a >65-line function it does not touch lands." This issue has no acceptance criteria of its own. Tracking it separately risks the one hook being fixed twice, in two different ways.

    Recommendation: fold this issue's facts into #16191 and close it as a duplicate. The facts are two new offenders, lifespan.py's cleanup_services (267 body lines) and _init_graph_rag_service (68), and the CI finding below. Or keep it only as a sub-issue of #16191. Both are the filer's or coordinator's call, not mine. It's a sub-issue of umbrella #16238 as asked.

    One fact here is worth keeping, and I've checked it. enforce-precommit.yml runs every pre-commit hook with --from-ref HEAD^1 --to-ref HEAD^2 (:202) and turns findings into ::warning:: (:207-209). Only the gating hook, ssot-config-lib-guard, blocks (:250). So the block really is local-only. Separately, any fix that scopes a hook to the staged diff has to handle this job: under --from-ref, pre-commit stages nothing, so a staged-mode scope sees an empty change. pre-commit exports the range as PRE_COMMIT_FROM_REF (pre-commit 4.6.0, commands/run.py:391). #16241 hit exactly this for no-local-schemas and uses that variable. #16191's fix should do the same.

  2. added this to the v0.9.0 milestone on Sep 12, 2026
  3. mrveiss commented on Sep 12, 2026

    @mrveiss
    OwnerAuthor

    Stale-issue sweep (never auto-closed — Dev_new_gui wasn't GitHub's default branch at merge time). Leaving open — UNVERIFIABLE, not a guessed disposition.

    This issue has no acceptance-criteria checklist, only prose describing two possible fix directions. The delivering PR (#16241) says so itself: "#16250 (lifespan.py) is a third instance ... with no criteria of its own." Since there's nothing to tick against, I'm flagging this rather than closing on my own read.

    That said, strong evidence exists that the underlying scenario is resolved: autobot-infrastructure/shared/scripts/hooks/function_length_checker.py is now diff-scoped (added_lines/resolve_base/staged_paths from tools/lint/_scan_helpers.py) rather than whole-file — the literal complaint (a one-line unrelated edit to lifespan.py blocked by unrelated long functions) should no longer reproduce. Worth a quick manual check before closing, since the issue itself gives nothing to verify against formally.

  4. mrveiss commented on Sep 12, 2026

    @mrveiss
    OwnerAuthor

    Proposed acceptance criteria (derived from the report; the owner may amend). Related to #16186, where whole-file hooks block changes to lines nobody touched.

    • The function-length-check hook doesn't block a commit for functions the commit didn't change. It's diff-scoped, or it has a shrink-only baseline of pre-existing violations.
    • cleanup_services and _init_graph_rag_service in initialization/lifespan.py are brought under the limit, or recorded in that baseline with a removal issue.
    • A test proves a one-line change to a file that contains a long, untouched function commits cleanly, and that a newly lengthened function is still refused.
  5. mrveiss commented on Sep 13, 2026

    @mrveiss
    OwnerAuthor

    Closure evidence (batch 2c)

    Verified against origin/main (PR #16509, 20e7e6a). No checkboxes, so the Fix is taken as the criteria. All met. Body lines were counted with the checker's own rule (_count_body_lines in function_length_checker.py) applied to the origin/main text.

    Criterion Evidence
    cleanup_services under the 65-line ERROR threshold 13 body lines (autobot-backend/initialization/lifespan.py); it calls _stop_request_and_scheduled_work (11), _drain_background_work (8), _release_shared_resources (9)
    _init_graph_rag_service under 65 24 body lines; the mesh block moved to autobot-backend/initialization/neural_mesh_wiring.py (longest function 19)
    Nothing over 65 left behind 0 functions over 65 across lifespan.py, lifespan_shutdown.py and neural_mesh_wiring.py; the longest is initialize_background_services at 63 (WARNING band)
    The hook no longer blocks on functions the change didn't touch autobot-infrastructure/shared/scripts/hooks/function_length_checker.py _scope_to_change; tests pre-commit-function-length_test.py::test_a_one_line_change_beside_a_legacy_long_function_lands, test_editing_the_long_function_itself_still_fails, test_adding_a_new_long_function_still_fails. Shutdown order pinned by lifespan_shutdown_order_test.py::test_cleanup_runs_every_step_once_in_the_pinned_order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions