ticket: use base32 project record ids

This commit is contained in:
2026-06-09 22:10:47 +09:00
parent 0803bc3725
commit 4203988d74
798 changed files with 477 additions and 105 deletions
@@ -0,0 +1,91 @@
# Delegation intent: Hook context SystemItem append sink
## Intent
Implement the first step in the Task state/reminder cleanup sequence: add event-specific Hook context support with a host-mediated durable `SystemItem` append handle, while keeping Hook return actions as per-hook-point flow-control actions.
This is the prerequisite for moving TaskStore/reminder logic into the Task feature. Do not move TaskStore or Task reminders in this ticket.
## Worktree / branch
- worktree: `/home/hare/Projects/yoi/.worktree/hook-context-system-item-sink`
- branch: `work/hook-context-system-item-sink`
## Requirements
- Evolve the public Pod Hook API so Hook handlers receive event-specific context values rather than only bare summary inputs where necessary.
- Preserve the existing per-hook-point action/output types.
- Do not collapse actions into one global `HookDecision`.
- Add a host-created typed handle for durable model-visible `SystemItem` append.
- Suggested naming: `SystemItemAppendHandle`, `SystemItemSink`, or equivalent.
- Constructors/fields must stay host-private; feature/hook code can only use handles the host provides.
- The handle must not expose raw `llm_worker::Item`, raw history writers, raw event senders, raw `Pod`, raw `Worker`, or `NotifyBuffer`.
- The append path must use existing durable history semantics:
- host-controlled pending append / commit path;
- `LogEntry::SystemItem`;
- `Event::SystemItem`;
- model context visibility only after durable commit.
- The initial approved system-item requests should be narrow.
- Support what is needed for a future `TaskReminder` hook, and notification-like system items only if this falls out naturally from existing `SystemItem` machinery.
- Do not introduce arbitrary `llm_worker::Item` append or generic plugin event channels.
- Keep built-in internal modules distinct from external-plugin authority approval.
- It is okay to add scaffolding so internal hooks can receive the handle by host policy.
- Do not implement external-plugin approval or WASM imports in this ticket.
- Preserve current observable behavior.
- Current Task reminders should continue to be emitted by existing `PodInterceptor` logic until the follow-up ticket moves them.
- Existing Hook tests and permission hook behavior must continue to pass.
## Non-goals
- Moving `TaskStore` ownership into the Task feature.
- Moving `TaskReminderState` or `PodInterceptor` reminder logic.
- TUI UI/dialog work.
- Generic event channel / arbitrary UI payloads.
- External plugin loading or package approval.
- Changing ToolRegistry / PreToolCall permission behavior.
- Reintroducing raw `Item` injection, `ContinueWith(Vec<Item>)`, no-result tool skip, or arbitrary `ToolResult` construction.
## Suggested files
- `crates/pod/src/hook.rs`
- `crates/pod/src/ipc/interceptor.rs`
- `crates/pod/src/pod.rs`
- `crates/pod/src/controller.rs`
- `crates/session-store/src/system_item.rs` or wherever `SystemItem` request/serialization is defined
- existing Hook tests in `crates/pod/src/**`
## Validation
Run at least:
- focused Hook context / SystemItem sink tests added by this ticket
- `cargo test -p pod hook --lib`
- `cargo test -p pod --lib`
- `cargo test -p llm-worker --lib`
- `cargo check --workspace --all-targets`
- `cargo fmt --check`
- `./tickets.sh doctor`
- `git diff --check`
Run `nix build .#yoi` if feasible.
## Escalate if
- Implementing the handle requires changing session/history commit semantics.
- The only easy path is to expose raw `Item`, raw history writers, raw event senders, or `Pod`/`Worker` internals.
- Hook action types would need to be merged into one generic return type.
- Current Task reminder behavior would change before the Task ownership follow-up.
## Completion report
Report:
- worktree path / branch
- commit hash
- changed files
- Hook context/action API changes
- SystemItem append handle design and path to durable commit
- tests added/updated
- validation results
- unresolved risks/follow-ups
- whether ready for external review
@@ -0,0 +1,57 @@
# Review: hook-context-system-item-sink
## 1. Result: approve
Approve. I found no blockers for merging `04a4a73 pod: add hook system item sink` against the stated prerequisite scope.
## 2. Summary of implementation
The implementation changes the `PreLlmRequest` hook input from bare `PreRequestInfo` to `PreRequestContext`, while leaving hook return types event-specific and flow-control-only. `PreRequestContext` carries the existing request summary plus an optional `SystemItemAppendHandle`.
`SystemItemAppendHandle` is host-constructed (`pub(crate) fn new`), has private storage, and exposes only `append_task_reminder(...)`, which queues a typed `SystemItem::TaskReminder`. `PodInterceptor::pre_llm_request` creates a per-request queue only when a log writer exists, passes the handle through the hook context, and after all pre-request hooks continue successfully drains the queue, commits each item through the existing `SystemItemCommitter` / `LogEntry::SystemItem` path, and returns the rendered history items via the internal `PreRequestAction::ContinueWith` lane.
The existing Task reminder implementation remains in `PodInterceptor::pending_history_appends()` and Task ownership is not moved in this ticket.
## 3. Requirement-by-requirement assessment
- **Hook return actions remain per-hook-point flow-control types:** Satisfied. `HookPromptAction`, `HookPreRequestAction`, `HookPreToolAction`, `HookPostToolAction`, and `HookTurnEndAction` remain distinct. `HookPreRequestAction` still exposes only `Continue`, `Cancel`, and `Yield`; it does not expose `ContinueWith(Vec<Item>)`.
- **Public API avoids raw internals and generic effects:** Satisfied for the changed Hook surface. The new handle does not expose raw `llm_worker::Item`, history writers, event senders, `Pod`, `Worker`, `NotifyBuffer`, internal interceptor actions, no-result skip, arbitrary `ToolResult` construction, or a generic event/UI channel. Existing pre-tool denial still maps an error string to an internal synthetic result, not an arbitrary public `ToolResult`.
- **`SystemItemAppendHandle` host-private construction and narrow approved surface:** Satisfied. The constructor and backing queue are crate-private/private, and public hook code can only request a task-reminder system item through `append_task_reminder`.
- **Durable model-visible append path:** Satisfied within existing semantics. Hook-queued items are committed through the existing `SystemItemCommitter` path as `LogEntry::SystemItem`, which in production publishes through the segment log sink as `Event::SystemItem`; only then are corresponding model-visible history items returned to the worker through the internal interceptor action.
- **Successful-continue-only injection:** Satisfied by code. `pre_llm_request` returns immediately on the first non-continue hook action before draining the local queue, so queued hook items are dropped on cancel/yield and are committed/injected only when all hooks continue.
- **Task reminder behavior preserved:** Satisfied. `TaskStore`, `TaskReminderState`, `task_reminder_system_item`, `pending_history_appends`, and task-tool reset behavior remain in `PodInterceptor`; the follow-up ticket remains responsible for moving Task ownership into the Task feature.
- **Existing permission/hook behavior remains conceptually valid:** Satisfied. Tool hook contexts remain bounded summaries; public pre-tool actions still provide only continue/deny/abort/pause, with no no-result skip or arbitrary tool result path.
- **Tests:** Mostly satisfied. Added tests cover handle queueing of an approved task reminder, context handle absence, commit plus returned system message behavior, and no-log-writer behavior. Existing tests continue to cover public hook action restrictions and current task reminder lanes. The only test gap I noted is explicit append-then-cancel/yield no-leak coverage, but the implementation path is straightforward enough that I do not consider this a merge blocker.
- **No broad refactor / no external-plugin approval implementation:** Satisfied. The diff is limited to `crates/pod/src/hook.rs`, `crates/pod/src/ipc/interceptor.rs`, and a small `PreRequestContext` type update in `crates/pod/src/pod.rs`.
## 4. Blockers
None.
## 5. Non-blockers / follow-ups
- Add an explicit regression test for a pre-request hook that appends through `SystemItemAppendHandle` followed by a later hook returning `Cancel` or `Yield`, asserting that no commit and no `ContinueWith` occur. The code already behaves this way, but the intended no-leak invariant is important enough to lock down.
- Before any external plugin/user-script hook surface is enabled, add per-hook or per-feature authority policy for whether `PreRequestContext::system_items()` is present. This ticket intentionally avoids external-plugin approval, and current built-in/internal hook usage is acceptable.
## 6. Validation assessed or rerun
Assessed:
- Reviewed ticket, delegation intent, investigation note, authority-context decision, and dependent Task ownership follow-up.
- Reviewed `git diff develop...HEAD`; changed files are limited to:
- `crates/pod/src/hook.rs`
- `crates/pod/src/ipc/interceptor.rs`
- `crates/pod/src/pod.rs`
- Inspected the relevant public hook API, handle construction/surface, interceptor commit path, and task reminder preservation tests.
Rerun:
- `cd /home/hare/Projects/yoi/.worktree/hook-context-system-item-sink && git diff --check develop...HEAD` — passed with no output.
Not rerun:
- I did not rerun `cargo test`, `cargo check`, or `nix build` from this external-reviewer turn because the requested validation allowance was read-only and those commands would write build artifacts. I did not find a coder validation report in the ticket thread.
## 7. Residual risk
The remaining risk is in future authority granularity, not this prerequisite implementation: today the handle is present for pre-request hooks when a log writer exists, rather than being selected per installed feature/hook. That should be tightened before exposing hooks to untrusted external plugins. The existing `SystemItemCommitter` API also logs and drops commit failures rather than returning a result; this is pre-existing behavior shared by other SystemItem lanes, but it means disk-write failure handling is not made stronger by this ticket.
@@ -0,0 +1,18 @@
# Investigation: Task state and Hook side-effect boundary
## Findings
- Hook action types are already separated per hook point after Hook hardening. The next design should preserve that: flow-control actions stay event-specific rather than becoming one global `HookDecision`.
- Hook inputs are still summary structs, not contexts with host-created handles. That is the missing abstraction for feature-owned behavior that needs durable host side effects.
- `TaskStore` is still owned by `Pod`, and `TaskReminderState`/reminder emission is still owned by `PodInterceptor`.
- The Task built-in feature module currently contributes only the four Task tools and receives `TaskStore` from Pod. This is an incomplete internal-module boundary: Task-specific state still remains on the Pod side.
- `SystemItem::TaskReminder` is currently appended through `PodInterceptor::pending_history_appends()`, which is the correct durable history direction but the wrong ownership location for Task-specific logic.
## Decision
Split follow-up into two steps:
1. Add Hook context host handles, especially a durable `SystemItem` append handle. Hook returns remain per-hook-point flow-control actions. No raw `Item` injection and no generic effect/event channel.
2. Move TaskStore and Task reminder logic into the Task feature module, implemented as Task-owned tools plus hooks that use the host-provided SystemItem append handle.
This keeps Pod responsible for generic host surfaces and history authority, while Task owns Task-specific state and policy.
+66
View File
@@ -0,0 +1,66 @@
---
title: "Hook: add context handles for host-mediated SystemItem append"
state: "closed"
created_at: "2026-06-05T00:48:07Z"
updated_at: "2026-06-05T01:26:06Z"
---
## Issue
Built-in feature modules need a closed way to influence Pod-side behavior without adding feature-specific logic back into `Pod` / `PodInterceptor`. Task reminders are the immediate example: a Task feature should be able to observe request/tool activity and append a `SystemItem::TaskReminder`, but it should not receive `Pod`, `Worker`, raw history writers, raw `llm_worker::Item` injection, or a generic effect channel.
The current Hook surface already has per-hook-point action types after `hook-public-surface-hardening`, and those action types should remain flow-control oriented. The missing piece is event-specific Hook context carrying host-owned handles for allowed side effects, especially a durable `SystemItem` append path.
## Current findings
- `crates/pod/src/hook.rs` already distinguishes hook point output types such as `HookPromptAction`, `HookPreRequestAction`, `HookPreToolAction`, `HookPostToolAction`, and `HookTurnEndAction`.
- `PreLlmRequest` / `OnTurnEnd` public actions no longer expose raw `Item` injection.
- Hook inputs are currently summary structs (`PreRequestInfo`, `ToolCallSummary`, etc.), not context objects with host handles.
- `TaskReminder` emission currently lives in `PodInterceptor::pending_history_appends()` and uses Pod-owned `TaskStore` / `TaskReminderState`.
- Existing durable model-visible path is `SystemItem` commit -> `LogEntry::SystemItem` -> `Event::SystemItem` / model context, and this path must remain the only model-visible append mechanism.
## Direction
Introduce event-specific Hook context objects that carry narrow, host-created handles. Keep Hook return values as per-hook-point flow-control actions.
- Side effects are not returned as arbitrary `HookEffect` enums.
- Side effects are requested through typed handles on the Hook context.
- Handles have private constructors and are created only by the Pod host.
- Missing authority/handle should prevent installation or make the handle unavailable; runtime rejection is defense-in-depth, not the normal API path.
## Requirements
- Define event-specific Hook context types, or evolve `HookEventKind::Input` into context values without losing the existing per-event action types.
- `PreLlmRequest` context should be able to carry request summary plus a SystemItem append handle where the host grants it.
- Tool hook contexts should continue to expose bounded call/result summaries.
- Add a host-owned `SystemItemAppendHandle` / sink concept for model-visible durable system items.
- It must not expose raw `llm_worker::Item` or raw history writer access.
- It should append/push only approved `SystemItem` request kinds, initially including TaskReminder/Notification-like system items as needed.
- Actual commit timing remains host-controlled through the existing pending history append / `LogEntry::SystemItem` / `Event::SystemItem` path.
- Preserve per-hook-point flow-control action types.
- Do not collapse every hook into one generic `HookDecision`.
- Do not reintroduce `ContinueWith(Vec<Item>)`, no-result tool skip, arbitrary `ToolResult` construction, or hidden context mutation.
- Keep internal built-in module usage distinct from external-plugin authority approval.
- Built-in modules may receive host handles according to host policy.
- Future external plugins receive model-visible append handles only when the external-plugin authority model grants them.
- Provide tests showing:
- Hook actions remain flow-control only;
- model-visible side effects use the SystemItem append handle;
- no raw `Item` / raw history writer / raw event sender is exposed through public Hook context;
- missing/unavailable handles do not produce invisible context injection.
## Non-goals
- Moving TaskStore/reminder state into the Task feature; that is tracked by `task-feature-own-store-reminder-hooks`.
- TUI dialog/custom UI work.
- Generic plugin event channels.
- External plugin loading/WASM boundary implementation.
- Changing ToolRegistry / PreToolCall permission behavior.
## Acceptance criteria
- Hook contexts can carry host-owned typed handles for allowed side effects, starting with durable SystemItem append.
- Hook return values remain event-specific flow-control actions.
- Model-visible additions through Hooks are committed through the durable SystemItem path and are user-inspectable.
- Public Hook APIs still do not expose raw `Item` injection, raw Pod/Worker/session internals, or generic UI/event payload channels.
- The resulting API is sufficient for a later Task reminder Hook to append `SystemItem::TaskReminder` without Pod-specific Task logic in `PodInterceptor`.
+1
View File
@@ -0,0 +1 @@
Added PreRequestContext and host-mediated SystemItemAppendHandle for pre-request hooks. Hook returns remain per-hook-point flow-control actions; the append handle has host-private construction and a narrow task-reminder request surface; queued system items commit through the existing LogEntry::SystemItem / Event::SystemItem path only on successful continue. Existing Task reminder ownership remains unchanged for the follow-up ticket. External review approved. Merge validation passed: cargo test -p pod hook --lib, cargo test -p pod --lib, cargo test -p llm-worker --lib, cargo fmt --check, cargo check --workspace --all-targets, ./tickets.sh doctor, git diff --check, nix build .#yoi, ./result/bin/yoi pod --help.
+206
View File
@@ -0,0 +1,206 @@
<!-- event: create author: tickets.sh at: 2026-06-05T00:48:07Z -->
## Created
Created by tickets.sh create.
---
<!-- event: decision author: hare at: 2026-06-05T00:49:53Z -->
## Decision
# Investigation: Task state and Hook side-effect boundary
## Findings
- Hook action types are already separated per hook point after Hook hardening. The next design should preserve that: flow-control actions stay event-specific rather than becoming one global `HookDecision`.
- Hook inputs are still summary structs, not contexts with host-created handles. That is the missing abstraction for feature-owned behavior that needs durable host side effects.
- `TaskStore` is still owned by `Pod`, and `TaskReminderState`/reminder emission is still owned by `PodInterceptor`.
- The Task built-in feature module currently contributes only the four Task tools and receives `TaskStore` from Pod. This is an incomplete internal-module boundary: Task-specific state still remains on the Pod side.
- `SystemItem::TaskReminder` is currently appended through `PodInterceptor::pending_history_appends()`, which is the correct durable history direction but the wrong ownership location for Task-specific logic.
## Decision
Split follow-up into two steps:
1. Add Hook context host handles, especially a durable `SystemItem` append handle. Hook returns remain per-hook-point flow-control actions. No raw `Item` injection and no generic effect/event channel.
2. Move TaskStore and Task reminder logic into the Task feature module, implemented as Task-owned tools plus hooks that use the host-provided SystemItem append handle.
This keeps Pod responsible for generic host surfaces and history authority, while Task owns Task-specific state and policy.
---
<!-- event: plan author: hare at: 2026-06-05T01:01:20Z -->
## Plan
# Delegation intent: Hook context SystemItem append sink
## Intent
Implement the first step in the Task state/reminder cleanup sequence: add event-specific Hook context support with a host-mediated durable `SystemItem` append handle, while keeping Hook return actions as per-hook-point flow-control actions.
This is the prerequisite for moving TaskStore/reminder logic into the Task feature. Do not move TaskStore or Task reminders in this ticket.
## Worktree / branch
- worktree: `/home/hare/Projects/yoi/.worktree/hook-context-system-item-sink`
- branch: `work/hook-context-system-item-sink`
## Requirements
- Evolve the public Pod Hook API so Hook handlers receive event-specific context values rather than only bare summary inputs where necessary.
- Preserve the existing per-hook-point action/output types.
- Do not collapse actions into one global `HookDecision`.
- Add a host-created typed handle for durable model-visible `SystemItem` append.
- Suggested naming: `SystemItemAppendHandle`, `SystemItemSink`, or equivalent.
- Constructors/fields must stay host-private; feature/hook code can only use handles the host provides.
- The handle must not expose raw `llm_worker::Item`, raw history writers, raw event senders, raw `Pod`, raw `Worker`, or `NotifyBuffer`.
- The append path must use existing durable history semantics:
- host-controlled pending append / commit path;
- `LogEntry::SystemItem`;
- `Event::SystemItem`;
- model context visibility only after durable commit.
- The initial approved system-item requests should be narrow.
- Support what is needed for a future `TaskReminder` hook, and notification-like system items only if this falls out naturally from existing `SystemItem` machinery.
- Do not introduce arbitrary `llm_worker::Item` append or generic plugin event channels.
- Keep built-in internal modules distinct from external-plugin authority approval.
- It is okay to add scaffolding so internal hooks can receive the handle by host policy.
- Do not implement external-plugin approval or WASM imports in this ticket.
- Preserve current observable behavior.
- Current Task reminders should continue to be emitted by existing `PodInterceptor` logic until the follow-up ticket moves them.
- Existing Hook tests and permission hook behavior must continue to pass.
## Non-goals
- Moving `TaskStore` ownership into the Task feature.
- Moving `TaskReminderState` or `PodInterceptor` reminder logic.
- TUI UI/dialog work.
- Generic event channel / arbitrary UI payloads.
- External plugin loading or package approval.
- Changing ToolRegistry / PreToolCall permission behavior.
- Reintroducing raw `Item` injection, `ContinueWith(Vec<Item>)`, no-result tool skip, or arbitrary `ToolResult` construction.
## Suggested files
- `crates/pod/src/hook.rs`
- `crates/pod/src/ipc/interceptor.rs`
- `crates/pod/src/pod.rs`
- `crates/pod/src/controller.rs`
- `crates/session-store/src/system_item.rs` or wherever `SystemItem` request/serialization is defined
- existing Hook tests in `crates/pod/src/**`
## Validation
Run at least:
- focused Hook context / SystemItem sink tests added by this ticket
- `cargo test -p pod hook --lib`
- `cargo test -p pod --lib`
- `cargo test -p llm-worker --lib`
- `cargo check --workspace --all-targets`
- `cargo fmt --check`
- `./tickets.sh doctor`
- `git diff --check`
Run `nix build .#yoi` if feasible.
## Escalate if
- Implementing the handle requires changing session/history commit semantics.
- The only easy path is to expose raw `Item`, raw history writers, raw event senders, or `Pod`/`Worker` internals.
- Hook action types would need to be merged into one generic return type.
- Current Task reminder behavior would change before the Task ownership follow-up.
## Completion report
Report:
- worktree path / branch
- commit hash
- changed files
- Hook context/action API changes
- SystemItem append handle design and path to durable commit
- tests added/updated
- validation results
- unresolved risks/follow-ups
- whether ready for external review
---
<!-- event: review author: hare at: 2026-06-05T01:25:03Z status: approve -->
## Review: approve
# Review: hook-context-system-item-sink
## 1. Result: approve
Approve. I found no blockers for merging `04a4a73 pod: add hook system item sink` against the stated prerequisite scope.
## 2. Summary of implementation
The implementation changes the `PreLlmRequest` hook input from bare `PreRequestInfo` to `PreRequestContext`, while leaving hook return types event-specific and flow-control-only. `PreRequestContext` carries the existing request summary plus an optional `SystemItemAppendHandle`.
`SystemItemAppendHandle` is host-constructed (`pub(crate) fn new`), has private storage, and exposes only `append_task_reminder(...)`, which queues a typed `SystemItem::TaskReminder`. `PodInterceptor::pre_llm_request` creates a per-request queue only when a log writer exists, passes the handle through the hook context, and after all pre-request hooks continue successfully drains the queue, commits each item through the existing `SystemItemCommitter` / `LogEntry::SystemItem` path, and returns the rendered history items via the internal `PreRequestAction::ContinueWith` lane.
The existing Task reminder implementation remains in `PodInterceptor::pending_history_appends()` and Task ownership is not moved in this ticket.
## 3. Requirement-by-requirement assessment
- **Hook return actions remain per-hook-point flow-control types:** Satisfied. `HookPromptAction`, `HookPreRequestAction`, `HookPreToolAction`, `HookPostToolAction`, and `HookTurnEndAction` remain distinct. `HookPreRequestAction` still exposes only `Continue`, `Cancel`, and `Yield`; it does not expose `ContinueWith(Vec<Item>)`.
- **Public API avoids raw internals and generic effects:** Satisfied for the changed Hook surface. The new handle does not expose raw `llm_worker::Item`, history writers, event senders, `Pod`, `Worker`, `NotifyBuffer`, internal interceptor actions, no-result skip, arbitrary `ToolResult` construction, or a generic event/UI channel. Existing pre-tool denial still maps an error string to an internal synthetic result, not an arbitrary public `ToolResult`.
- **`SystemItemAppendHandle` host-private construction and narrow approved surface:** Satisfied. The constructor and backing queue are crate-private/private, and public hook code can only request a task-reminder system item through `append_task_reminder`.
- **Durable model-visible append path:** Satisfied within existing semantics. Hook-queued items are committed through the existing `SystemItemCommitter` path as `LogEntry::SystemItem`, which in production publishes through the segment log sink as `Event::SystemItem`; only then are corresponding model-visible history items returned to the worker through the internal interceptor action.
- **Successful-continue-only injection:** Satisfied by code. `pre_llm_request` returns immediately on the first non-continue hook action before draining the local queue, so queued hook items are dropped on cancel/yield and are committed/injected only when all hooks continue.
- **Task reminder behavior preserved:** Satisfied. `TaskStore`, `TaskReminderState`, `task_reminder_system_item`, `pending_history_appends`, and task-tool reset behavior remain in `PodInterceptor`; the follow-up ticket remains responsible for moving Task ownership into the Task feature.
- **Existing permission/hook behavior remains conceptually valid:** Satisfied. Tool hook contexts remain bounded summaries; public pre-tool actions still provide only continue/deny/abort/pause, with no no-result skip or arbitrary tool result path.
- **Tests:** Mostly satisfied. Added tests cover handle queueing of an approved task reminder, context handle absence, commit plus returned system message behavior, and no-log-writer behavior. Existing tests continue to cover public hook action restrictions and current task reminder lanes. The only test gap I noted is explicit append-then-cancel/yield no-leak coverage, but the implementation path is straightforward enough that I do not consider this a merge blocker.
- **No broad refactor / no external-plugin approval implementation:** Satisfied. The diff is limited to `crates/pod/src/hook.rs`, `crates/pod/src/ipc/interceptor.rs`, and a small `PreRequestContext` type update in `crates/pod/src/pod.rs`.
## 4. Blockers
None.
## 5. Non-blockers / follow-ups
- Add an explicit regression test for a pre-request hook that appends through `SystemItemAppendHandle` followed by a later hook returning `Cancel` or `Yield`, asserting that no commit and no `ContinueWith` occur. The code already behaves this way, but the intended no-leak invariant is important enough to lock down.
- Before any external plugin/user-script hook surface is enabled, add per-hook or per-feature authority policy for whether `PreRequestContext::system_items()` is present. This ticket intentionally avoids external-plugin approval, and current built-in/internal hook usage is acceptable.
## 6. Validation assessed or rerun
Assessed:
- Reviewed ticket, delegation intent, investigation note, authority-context decision, and dependent Task ownership follow-up.
- Reviewed `git diff develop...HEAD`; changed files are limited to:
- `crates/pod/src/hook.rs`
- `crates/pod/src/ipc/interceptor.rs`
- `crates/pod/src/pod.rs`
- Inspected the relevant public hook API, handle construction/surface, interceptor commit path, and task reminder preservation tests.
Rerun:
- `cd /home/hare/Projects/yoi/.worktree/hook-context-system-item-sink && git diff --check develop...HEAD` — passed with no output.
Not rerun:
- I did not rerun `cargo test`, `cargo check`, or `nix build` from this external-reviewer turn because the requested validation allowance was read-only and those commands would write build artifacts. I did not find a coder validation report in the ticket thread.
## 7. Residual risk
The remaining risk is in future authority granularity, not this prerequisite implementation: today the handle is present for pre-request hooks when a log writer exists, rather than being selected per installed feature/hook. That should be tightened before exposing hooks to untrusted external plugins. The existing `SystemItemCommitter` API also logs and drops commit failures rather than returning a result; this is pre-existing behavior shared by other SystemItem lanes, but it means disk-write failure handling is not made stronger by this ticket.
---
<!-- event: close author: hare at: 2026-06-05T01:26:06Z status: closed -->
## Closed
Added PreRequestContext and host-mediated SystemItemAppendHandle for pre-request hooks. Hook returns remain per-hook-point flow-control actions; the append handle has host-private construction and a narrow task-reminder request surface; queued system items commit through the existing LogEntry::SystemItem / Event::SystemItem path only on successful continue. Existing Task reminder ownership remains unchanged for the follow-up ticket. External review approved. Merge validation passed: cargo test -p pod hook --lib, cargo test -p pod --lib, cargo test -p llm-worker --lib, cargo fmt --check, cargo check --workspace --all-targets, ./tickets.sh doctor, git diff --check, nix build .#yoi, ./result/bin/yoi pod --help.
---