Skip to content

fix(zcode): keep a team-configured hook timeout instead of the per-event default - #582

Merged
jeff-r2026 merged 1 commit into
Tencent:mainfrom
Dev-next-gen:fix/zcode-honor-configured-hook-timeout
Sep 16, 2026
Merged

jeff-r2026 merged 1 commit into
Tencent:mainfrom
Dev-next-gen:fix/zcode-honor-configured-hook-timeout

Conversation

@Dev-next-gen

Copy link
Copy Markdown
Contributor

Summary

toZcodeEntry reads its timeoutMs only from the ZCODE_TIMEOUT_MS table introduced in #555 and never looks at def.timeout, so on ZCode a timeout the team wrote down is silently dropped: a timeout: on a hook in hooks/hooks.yaml, and the builtin.overrides.<key>.timeout knob the usage guide documents ("Only the timeout of a built-in hook can be overridden"). Before #555 the writer honored it (timeoutMs: def.timeout * 1000). The per-event table is the right default for the builtin dispatch hooks — a session-start pull really does need more than the 10–15s shell defaults — but it also took over the values a team had stated explicitly.

I kept the table as the default and let a stated timeout win, which is what every other tool's writer already does.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

Test Plan

  • npx tsc --noEmit passes
  • npx vitest run passes (see scope note below)
  • Added/updated tests for the change

End-to-end with the built CLI, single-repo mode, --agent zcode, .teamai/hooks/hooks.yaml:

hooks:
  - id: slow-sync
    description: nightly sync that needs five minutes
    event: Stop
    command: my-slow-sync
    timeout: 300
builtin:
  overrides:
    Hook dispatch stop:
      timeout: 240

After npm run build and teamai hooks inject, the Stop entries in .zcode/cli/config.json:

before   teamai hook-dispatch stop --tool zcode     timeoutMs = 60000
         my-slow-sync                               timeoutMs = 60000

after    teamai hook-dispatch stop --tool zcode     timeoutMs = 240000
         my-slow-sync                               timeoutMs = 300000

Unit side, src/__tests__/zcode.test.ts gains one case driving reconcileHooks(..., 'zcode', ...) with both fields. On the current main it fails with expected 60000 to be 300000; with the change the whole ZCode file passes (11/11).

I also ran the neighbouring hook suites — hooks-golden, hooks-team, hooks-dispatch-format, builtin-hooks, hooks-reconcile-scope, hooks-hasteamaihooks, hooks-security, hooks-shell-check — 72/72 green. The golden fixtures matter here: builtinHookDefs sets withTimeout = false for zcode, so builtin defs carry no timeout and the rendered output for a config without overrides is byte-identical. Only a config that states a timeout changes.

Scope note, so you can weigh it: I ran the suite on Windows, where a number of pre-existing cases fail for reasons unrelated to this change (POSIX path separators asserted in test strings, 0600 mode checks, git-backed fixtures timing out). The eight suites above and the full ZCode file are green here, and none of the touched code is platform-conditional beyond the win32 branch #555 added, which this change leaves alone.

Related Issues

Follow-up to #555, which added the per-event table.

Notes for Reviewers

The one judgement call is precedence. I read the table as ZCode's default rather than an override, because HookDef.timeout is documented as "per-hook timeout in seconds (tool-specific; omitted = tool default)" and the guide lists builtin.overrides.<key>.timeout as a supported knob. If you would rather the table stay a hard floor for the builtin dispatch hooks and only team hooks from hooks.yaml be honored, that is a one-line change in the same spot and I am happy to make it.

I did not add a CHANGELOG entry: most recent fixes here don't carry one, so it looked like something you curate at release time. Say the word and I will add it.

Found by a defect-hunting pipeline I build and run (Dev-next-gen), using Claude Code with Anthropic's Claude Opus 5.

…ent default

toZcodeEntry took its timeoutMs only from the ZCODE_TIMEOUT_MS table added in
Tencent#555 and never looked at def.timeout, so on ZCode a timeout the team wrote down
was silently discarded: a `timeout:` on a hook in hooks/hooks.yaml, and the
`builtin.overrides.<key>.timeout` knob documented in the usage guide. Before
Tencent#555 the writer honored it (`timeoutMs: def.timeout * 1000`); the table is the
right default for the builtin dispatch hooks, but it took over the explicit
values too.

Observed end-to-end with the built CLI: a team hook declaring `timeout: 300`
and `builtin.overrides."Hook dispatch stop".timeout: 240` both landed in
.zcode/cli/config.json as `timeoutMs: 60000`. Every other tool honors the same
fields, so a hook long enough to matter on ZCode was capped at the default and
killed mid-run.

The table now serves as the default only, and a stated timeout wins. Builtin
defs for zcode carry no timeout (builtinHookDefs sets withTimeout false for the
tool), so the rendered output for a config without overrides is unchanged --
hooks-golden stays green.
@jeff-r2026
jeff-r2026 merged commit 78a68d6 into Tencent:main Sep 16, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants