Skip to content

Add before and after hooks for component expansion and bound commands #956

Open

Description

@taras

Story

Component authors can observe component expansion and bound shell commands before and after execution without being responsible for invoking the operation or returning its result.

The approved factory returns the operation and two independent registration functions:

const { expand, beforeExpand, afterExpand } =
  createHooks<"expand", TArgs, TResult>(...);

yield* beforeExpand(recordExpansionStart);
yield* afterExpand(recordExpansionEnd);
const value = yield* expand(args);

The constructor arguments are resolved in the implementation plan; the returned names and the behavior below are the accepted contract.

Current gap

Component.expand and Component.applyBoundModifiers expose continuation middleware, then separately enforce invocation count and preserve the outcome that core produced. Their instrumentation needs before/after hooks, while core owns execution and settlement.

The approved design is recorded in #954, under Middleware and hooks in architecture.md, with architecture rules 33–40. The adapter has no implementation in that PR.

Contract and acceptance

  • createHooks composes the existing createApi without modifying that dependency. Hook registration is scoped and exposes neither next nor a replacement return channel.
  • The owner invokes the implementation once after before hooks complete normally. A throwing before hook prevents the implementation from starting.
  • After hooks receive the arguments and Effection's Result<TResult>: success, the before-hook rejection or implementation failure, or a dedicated cancellation error. Cancellation still unwinds as cancellation.
  • Before hooks run outer to inner; independently registered after hooks run inner to outer, including when a before hook rejects execution. One failing after hook does not skip the remaining after hooks. Every after hook observes the same outcome selected before after hooks run.
  • A failing after hook is reported without changing a completed effect or its saved result. An operation failure remains primary when both fail. The adapter never retries the operation to recover from a hook failure.
  • The call owns hook work and waits for cleanup. Concurrent calls remain independent, and separately loaded package copies preserve the existing scoped composition behavior.
  • Migrate component-expansion and bound-command observation as real production consumers. Preserve their progress reporting, bound process results, timeout behavior, cancellation and teardown. Remove delegation bookkeeping only where the adapter replaces its responsibility.
  • Update the affected public references and conformance clauses with the migration. Ordinary modifier replacement, generated evaluation admission and durable ownership retain their own contracts.

Evidence

Use focused adapter regressions and the production consumers. A before-hook rejection performs no underlying work but reaches after hooks as a failure; a completed effect followed by a hook failure is not repeated; cancellation reaches after hooks and joins cleanup. Cover ordering, independent registration and scoped composition without adversarial native-object permutations.

Existing regression entry points include:

deno task test packages/core/tests/component-expansion.test.ts packages/core/tests/foreground-exec.test.ts packages/core/tests/exec-timeout.test.ts

The Planner chooses and freezes the exact affected evidence after tracing consumers and resolves package/export placement and the remaining constructor/type details before assigning implementation. A new material API or ownership decision returns to the Architect.

Dependencies and scope

Depends on the approved contract in #954. #957 classifies mixed APIs in parallel; #958 owns the broader defensive diagnostic/test cleanup. Related ownership work: #491. This issue owns the adapter and its first two consumers; it does not convert every middleware API or introduce a new permission, identity, persistence or provider protocol. Delivery completes when the implementation, first consumers and their updated references merge.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions