## Addendum: Current Helper Contract Rebaseline

This section is the current source of truth for `keble-helpers` before frontend
demo-to-prod. Helpers own shared schemas/protocols, not backend dispatch policy.

## Current Stage

- [x] Shared queue-neutral `QueuedEnvelope` schemas and processor protocol exist.
- [x] Shared `AgenticActionEvent` / `AgenticEventEmitter` event primitives exist.
- [x] Shared `AgentToolConfig.build(...)` and `AgenticEventEmitter.build(...)`
  avoid standalone normalizer proliferation.
- [x] Celery app creation, Mongo ledger persistence, dispatch ordering, retries,
  and enqueue policy stay out of helpers.
- [ ] Future segmenting/positioning fanout should consume helper protocols, but
  backend remains the queue publisher.

```py
class QueuedEnvelopeProcessorProtocol(Protocol):
    """Package-neutral processing contract; backend owns publication."""

    processor_name: str

    async def aprocess_queued_envelope(
        self,
        context: QueuedEnvelopeProcessContext,
    ) -> QueuedEnvelopeProcessResult: ...
```

---

## Addendum: Schema-Owned Tool Config Build

This corrective pass replaces the just-added standalone registrar and callback
normalizers with schema-owned constructors so helper exports do not grow a
utility-function surface for every config/emitter object.

## Context From Current Chat

- [x] User flagged `normalize_*` helper proliferation as the wrong pattern.
- [x] Preferred shape is `Class.build(...)` on the owning Pydantic schema.
- [x] Helper package should provide one compact schema, not a growing set of
  top-level conversion helpers.

## Corrected Shape

- [x] Replace `normalize_agent_tool_config(...)` with
  `AgentToolConfig.build(...)`.
- [x] Replace `normalize_agentic_event_emitter(...)` with
  `AgenticEventEmitter.build(...)`.
- [x] Keep dict/model/none coercion at raw package registrar boundaries.
- [x] Remove `normalize_agent_tool_config` and
  `normalize_agentic_event_emitter` from helper exports.

```py
config = AgentToolConfig.build(
    {
        "name": "mutate_segmenting",
        "description": "Apply one typed segmenting action batch.",
        "requires_approval": True,
    }
)

emitter = AgenticEventEmitter.build([callback])
```

---

## Addendum: Shared Agentic Tool Config

This section records the current `keble-helpers 1.12.5` plan for package-owned
pydantic-ai tool registrars. Backend should compose deps and call package
registrars; packages should own the tool names, payload schemas, and execution
bodies.

## Goal

- [x] Add shared `AgentToolConfig`.
- [x] Add schema-owned `AgentToolConfig.build(...)`.
- [x] Keep helper ownership limited to metadata: name, description, approval.
- [x] Let `keble-segmenting`, `keble-positioning`, and `keble-task` consume this
  config in package-owned registrars.
- [x] Keep backend from defining package mutation tool bodies manually.

```py
config = AgentToolConfig(
    name="mutate_task_workspace",
    description="Apply one typed task action batch.",
    requires_approval=True,
)
```

---

## Addendum: Shared Agentic Action Event Protocol

This section records the implemented `keble-helpers 1.12.4` event contract used
by task, segmenting, positioning, and backend action runtimes.

## Goal

- [x] Add one package-neutral event envelope: `AgenticActionEvent[T]`.
- [x] Add one lifecycle enum: `AgenticActionEventStatus`.
- [x] Add one ordered async emitter: `AgenticEventEmitter`.
- [x] Make callback failures propagate instead of being logged and ignored.
- [x] Keep Celery, SSE, FastAPI, and package-specific payloads out of helpers.

```py
event = AgenticActionEvent[MyActionResult](
    source="keble-task",
    action_type="CREATE_RELATED_TASK",
    status=AgenticActionEventStatus.SUCCEEDED,
    payload=result,
)
await emitter.aemit(event)
```

## Verification

- [x] Added helper tests for required event fields.
- [x] Added emitter order and fail-fast callback tests.
- [x] Built `keble_helpers-1.12.4-py3-none-any.whl`.

---

## Addendum: Universal Queued Envelope Contract

This additive plan makes `keble-helpers` the shared schema/protocol owner for generic queued work. Backend owns Celery and persistence; packages own whether they can process an envelope.

## Goal

- [x] Add shared queue-neutral envelope schemas.
- [x] Add shared processor protocol and typed processor result.
- [x] Keep Celery, Mongo ledger persistence, and retry policy out of `keble-helpers`.
- [x] Let backend and package clients share one small contract:
  `processor.aprocess_queued_envelope(context) -> QueuedEnvelopeProcessResult`.

## Phase 1. Shared Envelope Types

- [x] Add `QueuedEnvelope` with JSON-safe fields:
  - [x] `envelope_id`
  - [x] `job_type`
  - [x] `payload`
  - [x] `domain_refs`
  - [x] `trace_id`
  - [x] `created_at`
- [x] Add `QueuedEnvelopeProcessContext`.
- [x] Add `QueuedEnvelopeProcessResult`.
- [x] Export the types from `keble_helpers`.

```py
class QueuedEnvelope(BaseModel):
    """Queue-neutral message body shared by backend and package processors."""

    envelope_id: str
    job_type: str
    payload: dict[str, Any] = Field(default_factory=dict)
    domain_refs: dict[str, str] = Field(default_factory=dict)
    trace_id: str | None = None
    created_at: datetime
```

## Phase 2. Processor Protocol

- [x] Add `QueuedEnvelopeProcessorProtocol`.
- [x] Require processors to return `handled=False` when the job type is unrelated.
- [x] Require the first matching processor to own payload validation.
- [x] Do not put backend registry ordering into the helper package.

```py
class QueuedEnvelopeProcessorProtocol(Protocol):
    """Queue-neutral processor contract implemented by backend/package clients."""

    processor_name: str

    async def aprocess_queued_envelope(
        self,
        context: QueuedEnvelopeProcessContext,
    ) -> QueuedEnvelopeProcessResult: ...
```

## Phase 3. Tests And Docs

- [x] Add tests for envelope serialization.
- [x] Add tests for handled/success/result validation.
- [x] Add a protocol-compatible fake processor test.
- [x] Update README with the backend-owned-dispatch / package-owned-payload rule.
- [x] Bump package version and build the wheel for backend consumption.
