v4.2.3: task-metadata hook moves to PreToolUse(TaskCreate) - #63
Merged
Merged
Conversation
… reject v4.2.1 normalised stringified `tool_input.metadata` but the same hook kept rejecting valid TaskCreate calls in other sessions. Direct shell tests passed; the live harness still failed — symptom of a different envelope shape we couldn't see, because auto-mode (correctly) refuses to let an agent self-modify a plugin hook to capture the live payload. Make `scripts/task-created-tag-check.sh` envelope-agnostic. Extraction tries, in order: `tool_input.metadata` (object or JSON-string), `tool_input` (fields flattened directly), `.metadata` (no wrapper), payload-as-string parsed once, then a deep search across the JSON tree for `user_story` / `layer`. Whatever shape the harness uses, valid metadata is found. On rejection, write the raw payload + extraction trace to `$TMPDIR/code-et-task-hook/last-rejected.json` and reference that path in the error message. Next failure leaves the actual envelope on disk — no wrapper script, no auto-mode prompt. Twelve bats payload-shape regressions pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v4.2.2's diagnostic dump captured the live payload and revealed the real bug: the hook was wired to the TaskCreated *lifecycle* event, which fires after the task is in the store with a flat envelope (session_id, hook_event_name, task_id, task_subject, task_description) — no tool_input, no metadata. Every well-formed TaskCreate was getting rejected because the script read a field that lifecycle events never carry. TaskCreate's tool schema confirms metadata is a top-level call param, so the correct hook is PreToolUse matched on TaskCreate. Fires before the task is created with raw tool_input (including metadata) intact — agents that forget metadata get rejected pre-creation instead of orphaning a malformed task, and the existing extractor's first path (.tool_input.metadata) now matches the real envelope on the first try. Keeps v4.2.2's envelope-agnostic extractor and rejection-time payload dump — both still pay off the next time the contract drifts. Two new bats cases cover the real PreToolUse(TaskCreate) envelope (14/14). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR landed in two iterations driven by what the diagnostic dump revealed:
v4.2.2 (commit 7555fb3) — Made the extractor envelope-agnostic and added on-rejection payload dump to
$TMPDIR/code-et-task-hook/last-rejected.json. Necessary instrumentation because auto-mode (correctly) refused to let an agent self-modify a plugin hook to capture the live payload.v4.2.3 (commit 94117e2) — The dump revealed the actual bug: hook was wired to the
TaskCreatedlifecycle event, whose payload is flat (task_id,task_subject,task_description) with notool_inputormetadata. Every well-formed call was rejected because the script read a field lifecycle events never carry. Moved toPreToolUsematched onTaskCreate— fires before task creation with rawtool_input(includingmetadata) intact, perTaskCreate's tool schema.Both layers stay: v4.2.2's extractor + rejection dump are kept as defence-in-depth for the next time the envelope drifts.
Test plan
bats code-et-implementer/tests/task-created-tag-check.bats— 14/14 pass (7 original + 5 envelope-shape regressions from 4.2.2 + 2 new PreToolUse-envelope regressions).PreToolUse(TaskCreate)envelope with metadata → exit 0; same envelope without metadata → exit 2 + dump written./plugin update codein the blocked session, retry the failingTaskCreatecall — should pass when metadata is supplied, reject pre-creation when omitted.🤖 Generated with Claude Code