# Journey: Agentic pipeline customer invocation

The end-to-end shape of any one of the seven registered Cross-Domain Autonomous
Pipelines — from "the customer (or scheduler) hit Run" to "the operator queue
clears, the customer reads the output, the audit log closes." Use this single
template against each pipeline variant; the per-pipeline differences (trigger
surface, agent backbone, output schema, approval gate, customer-facing entry)
are listed in the "Pipeline variants" table at the end.

## Personas

- **Customer** — consenting user whose data / topic anchor seeds the run;
  customer-tier pipelines (`arete.weekly_review_draft`,
  `metis.course_from_byom`, `nisaba.edition_study_guide`) are invoked directly;
  operator-tier pipelines (`veritas.story_drafting`, `tara.seasonal_program`,
  `nyx.event_explainer_set`) run on the customer's behalf
- **Tenant scheduler** — cron-fires recurring pipelines per tenant policy
- **Pipeline orchestrator** — `@oshun/agentic-studio` dispatcher; resolves
  registry → plan DAG → sub-agent hand-offs
- **Lilith tone reviewer agent** — `lilith.tone-reviewer`; mandatory pre-check
- **Domain sub-agents** — vary by pipeline (see variants table)
- **Reviewer** — operator-studio editor / tenant-teacher / scholar-tier /
  user-self (varies by pipeline's final approval gate)

## Pre-conditions

- Pipeline is registered in `V1_PIPELINES`
  (`libs/oshun/agentic-studio/src/pipelines/v1-pipelines.ts`) with
  `lifecycleState: 'live'`
- Invoker's tier matches the pipeline's `invocationTier`
- Tool grants resolve cleanly via
  `libs/oshun/agent-pipelines/src/grants/resolver.ts` (none revoked / expired)
- `mandatoryApprovalGateIds` have a seated reviewer for the invoker's
  `(tenant, domain, tone-class)` triple
- Customer-tier: consent flags on the underlying data scope (Iris memory,
  journal, habits) are current
- Operator-tier: operator's authoring session is on `/operator/studio`

## Steps

### 1. Trigger / origin

The registry permits three origins. The shipped customer UI currently proves the
explicit `Run Now` path for `arete.weekly_review_draft`; the remaining surface
and scheduler origins stay unchecked until their adapters are wired.

- [ ] **Push notification** — customer taps a system push (e.g., "Your weekly
      review is ready"); deep-link payload carries `?pipeline=<id>&run_intent`
- [x] **Explicit `Run Now` button** — the Arete weekly-review draft uses the
      real lifecycle from `/arete/review`; other variants remain as stated in
      the table
- [ ] **Scheduled cron** — tenant scheduler fires per `PipelineSchedule`
      (`nextFireFor` in `@oshun/agentic-studio`)
- [ ] BFF receives the trigger (customer-tier: `apps/oshun/bff/src/<domain>/`;
      operator-tier: `apps/oshun/bff/src/admin/` via
      `admin-agentic-operations-store.ts`)
- [ ] Telemetry: `agentic_pipeline_triggered`
      `(pipelineId, trigger_origin, invoker_id, tenant_id)`

### 2. AgentRun row + envelope created

- [ ] Dispatcher resolves `pipelineId` against `PipelineRegistry`; rejects
      `lifecycleState: 'deprecated'` cleanly
- [ ] `effectivePipelineForTenant()` applies tenant `PipelineCustomization`
      (budget cap, approval gates, lineage overrides)
- [ ] Fresh `AgentRun` row written per `libs/contracts/src/common/agent-run.ts`
      (inputs, plan, tool-calls, intermediate-artifacts, evidence, cost-ledger,
      decision-rationale, output-bundles, status, provenance)
- [ ] State: `pending` → `planning` on dispatch
- [ ] **Verify**: `[operator/operator-admin.md](../operator/operator-admin.md)`
      admin inbox shows the new run with `runId`, `pipelineId`, `state`

### 3. Lilith policy pre-check (tone + crisis screens)

- [ ] Dispatcher calls `lilith.tone-reviewer` against seed inputs (topic anchor,
      BYOM bundle, mood signal, ephemeris anchor, etc.)
- [ ] Lilith returns `(allow | reduced | suppress)` plus a crisis-frame
      directive
- [ ] `suppress` → run `failed` with `lilith.suppressed`; trigger surface shows
      a soft handoff (Tara breath, Arete journal)
- [ ] `reduced` narrows audacity / tone-band ceiling on every downstream
      sub-agent dispatch; `allow` proceeds to `executing`
- [ ] **Verify**:
      `[journeys/crisis-aware-tone-policy.md](./crisis-aware-tone-policy.md)`
      for the suppress branch end-to-end

### 4. Tool execution loop (sub-domain hand-offs)

The plan DAG (`PlanDag` from `@oshun/agentic-studio/plans/plan-dag`) iterates
its stages; each stage dispatches sub-agents under the parent's budget/authority
envelope.

- [ ] Stage 1..N dispatch against `participatingAgentIds` with sub-budgets
      deducted from `totalBudgetCap`
- [ ] Authority envelope narrows or matches parent (never widens; enforced by
      `grants/resolver.ts`)
- [ ] Grounded-composition stages call `sophia.ground` (retrieve → rank → ground
      → cite); Isis-emitted artifacts call `generate.*` and return a
      `ProvenanceBundle` ref with the output
- [ ] **Verify**:
      `[journeys/sophia-grounded-answer.md](./sophia-grounded-answer.md)` for
      the retrieval-augmented composition path
- [ ] Every tool call appended to `AgentRun.toolCalls[]` with
      `(toolId, scope, capabilityModifiers, costUnitsUsed, ts)`
- [ ] Budget overshoot → `subagent_budget_exceeded`; parent retries without the
      tool or fails fast
- [ ] Depth cap (default 5) prevents runaway chains; cycle prevention rejects
      ancestor re-entry unless `allow_cycle=true` at root

### 5. Provenance trail accumulates (Isis hash chain)

- [ ] Each generated artifact's `ProvenanceBundle` carries the attribution chain
      `(rootAgent → ... → producingAgent)` plus consent, prompt, model,
      workflow, watermark, timestamp; bundle hash-chained to the previous
      artifact in the run (see `WALKTHROUGH/studio/domain-bridges/isis/`)
- [ ] **Verify**:
      `[journeys/citation-drift-resolution.md](./citation-drift-resolution.md)`
      for the hash-chain inspection flow
- [ ] Per-stage event log captures every dispatch, terminal state, and
      unused-budget return

### 6. Output assembly

- [ ] Final stage assembles the per-pipeline output schema (see variants table;
      matches `expectedOutputSchemaNames`)
- [ ] Output bundle written to `AgentRun.outputBundles[]` with provenance ref
- [ ] `buildPipelineObservabilityReport` records per-stage SLA, evidence
      completeness, human-touch points
- [ ] `detectPipelineDeviation` checks declared
      `(participatingAgentIds, expectedHandoffDepth, totalBudgetCap)` envelope;
      deviations route to operator review

### 7. Author review queue (gated)

State enters `awaiting_approval` until the gate clears.

- [ ] Run appears in the gate's reviewer queue (operator-studio editorial /
      scholar-tier / tenant-teacher / user inbox)
- [ ] **Verify**:
      `[journeys/editorial-review-approval.md](./editorial-review-approval.md)`
      for the operator review and decision flow
- [ ] Reviewer surfaces include the full `AgentRun` envelope (plan, tool-calls,
      evidence, provenance) — no black-box approval
- [ ] Reviewer can **approve** (`completed`), **request changes** (loops back to
      executing), or **deny** (`killed` with reason)
- [ ] `mandatoryApprovalGateIds` cannot be bypassed by tenant policy

### 8. Customer notification + entry point

- [ ] On `completed`, `notify.send` dispatches per quiet-hours and channel
      preferences (push, email, in-app)
- [ ] Notification copy pipeline-specific; deep-link carries `?run=<runId>` to
      the per-pipeline customer surface
- [ ] Quiet hours defer (not lose) per Iris policy
- [ ] Telemetry: `agentic_pipeline_notification_sent` /
      `..._notification_clicked`

### 9. Customer reads, can approve / edit / discard

- [ ] Customer lands on the per-pipeline surface (variants table); output
      visibly **synthetic** (Iris attribution + synthetic-content indicators)
- [ ] Actions available: **approve / publish** (where the final gate is
      user-self, e.g., `arete.weekly_review_draft`), **edit then publish**,
      **discard** (run state recorded; output suppressed), or **defer**
- [ ] Edits persist as an `AgentRun` continuation; never silently overwrite the
      synthetic attribution chain
- [ ] Discard writes `AgentRun.customerOutcome = 'discarded'` for human-touch
      tuning in pipeline observability

### 10. Audit-log entry written

- [ ] Terminal audit event:
      `agentic_pipeline_(completed | failed | killed | declined)` with full
      attribution chain, total cost units, gate decisions, customer outcome
- [ ] Per-tool audit entries queryable from
      `apps/oshun/bff/src/admin/admin-audit-investigation-store.ts`
- [ ] `AgentRun` row reaches a terminal state and cannot be reopened
- [ ] **Verify**: `[operator/operator-admin.md](../operator/operator-admin.md)`
      admin audit log shows the terminal event with the attribution chain

## Post-conditions

- `AgentRun` row terminal; `outputBundles` published or suppressed per customer
  outcome
- Pipeline observability metrics updated (SLA, evidence completeness,
  human-touch)
- Tool grants released; sub-budgets reconciled
- Provenance bundle(s) hash-chained and inspectable from
  `/operator/admin/isis/provenance`
- Notification delivered or deferred per quiet-hours; never lost
- Telemetry trail:
  `triggered → policy_checked → executing → review_gated → review_resolved → notification_sent → customer_outcome`

## Failure modes

- [ ] **Lilith suppress** — fails closed; trigger surface delivers a soft
      handoff; no partial artifact leaks
- [ ] **Budget overshoot** — sub-agent killed; parent retries without the tool
      or fails fast; budget reconciliation correct
- [ ] **Cycle attempted** — dispatch blocked at `grants/resolver.ts`; audit
      notes the attempt
- [ ] **Approval gate timeout** — held in `awaiting_approval`; SLA breach
      surfaces in the deviation report
- [ ] **Tool revoked mid-run** — `tool_revoked` event reaches the sub-agent on
      the next tool-call boundary; aborts or retries without the tool
- [ ] **Deprecated pipeline invoked** — dispatcher rejects with a clear
      alternative
- [ ] **Scheduler double-fire** — idempotent dispatch keys no-op the second
- [ ] **Customer discards** — output never reaches a customer-facing surface;
      provenance + audit retained for the configured window

## E2E coverage

- [`apps/oshun/web/e2e/agentic-pipeline-invocation.spec.ts`](../../apps/oshun/web/e2e/agentic-pipeline-invocation.spec.ts)
  — real HTTP integration against the live BFF `POST /v1/agentic/runs/execute`
  (the server-authoritative guarded tool-plan runner): request validation (400),
  the fail-closed unregistered-tool gate (503 `agent_tools_not_configured`), a
  guarded run of a registered read-only studio tool (200 with the `AgentRun`
  status + `executedCount`), and the kill-switch governance termination (the run
  halts before any tool executes). The customer trigger surface `/arete/review`
  is covered by `arete-weekly-review.spec.ts`.
- The customer **AgentRun lifecycle** (submit → approval-gate → approve/discard)
  has a real BFF surface — `POST/GET /v1/agentic/runs`, `POST …/:runId/approve`,
  `POST …/:runId/discard` — wrapping the `@oshun/agentic-studio` engine
  (`initialSubagentRunStatus`, `approvalRolePermitted`,
  `buildCompletionNotification`; never auto-completes). Proven at the BFF layer
  by `apps/oshun/bff/src/__tests__/agentic-runs-lifecycle-route.test.ts`.
- [`apps/oshun/web/e2e/agentic-pipeline-runnow-arete.spec.ts`](../../apps/oshun/web/e2e/agentic-pipeline-runnow-arete.spec.ts)
  — the customer **"Run Now"** affordance for the customer-tier
  `arete.weekly_review_draft` variant, on its natural home `/arete/review` (per
  the variants table). Drives the real BFF AgentRun lifecycle end to end through
  the UI: request a draft (steps 1–2 → `awaiting_approval`, the
  `user.confirm.before.publish` gate holds it before it proceeds), the invoker
  **confirms** (steps 7/9 → `queued`, released to the composer), and
  **discards** (step 9 → `cancelled`). The `/v1/agentic/**` calls are re-issued
  with a `domain:*` customer dev bearer. Component:
  `apps/oshun/web/src/components/lilith/AreteReviewDraftRun.tsx` (injected into
  `AreteReview`). It never asserts a fabricated completion — the surface
  honestly stops at `queued`.
- **Coverage depth**: deep for the customer-tier lifecycle surface (request →
  gate → confirm/discard, driven through the UI against the live BFF) plus the
  BFF execution & governance core — see [`coverage.md`](./coverage.md).
- **Uncovered (executor-bound, not artificially faked)**: the downstream
  **tool-execution loop** (steps 4–6: sub-agent DAG dispatch, `sophia.ground`
  composition, Isis provenance hash-chain) and the per-variant generation
  outputs run in the executor and stay **fail-closed without provider creds** —
  a confirmed run honestly rests at `queued` rather than fabricating a draft.
  The other six pipeline variants' trigger surfaces are contextual to their own
  domain pages (`/metis/byom`, `/nisaba`, operator `/operator/studio` &
  `/operator/admin`) and wire these same lifecycle routes when built. Budget-cap
  admission and DAG dispatch are exercised by
  `apps/oshun/bff/src/agentic/runs-route.test.ts`.

## Per-view files touched by this journey

Operator side (shared across all variants):

- [`operator/operator-admin.md`](../operator/operator-admin.md)
- [`operator/operator-studio.md`](../operator/operator-studio.md)
- [`operator/operator-admin-isis-provenance.md`](../operator/operator-admin-isis-provenance.md)

Customer side (per-pipeline):

- `veritas.story_drafting` →
  [`customer/05-veritas/veritas.md`](../customer/05-veritas/veritas.md),
  [`customer/05-veritas/veritas-claim.md`](../customer/05-veritas/veritas-claim.md)
- `metis.course_from_byom` →
  [`customer/08-metis/metis-byom.md`](../customer/08-metis/metis-byom.md),
  [`customer/08-metis/metis.md`](../customer/08-metis/metis.md)
- `tara.seasonal_program` →
  [`customer/03-tara/tara.md`](../customer/03-tara/tara.md),
  [`customer/03-tara/domains-tara-programs.md`](../customer/03-tara/domains-tara-programs.md)
- `nyx.event_explainer_set` →
  [`customer/06-nyx/nyx.md`](../customer/06-nyx/nyx.md),
  [`customer/06-nyx/domains-nyx-events.md`](../customer/06-nyx/domains-nyx-events.md)
- `arete.weekly_review_draft` →
  [`customer/04-arete/arete-review.md`](../customer/04-arete/arete-review.md)
- `nisaba.edition_study_guide` →
  [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md)

## Cross-references

- Feature spec:
  [`V1/features.md` § Cross-Domain Autonomous Pipelines](../../V1/features.md#cross-domain-autonomous-pipelines)
- Architecture:
  [`V1/ARCHITECTURE.md` § AgentRun lifecycle](../../V1/ARCHITECTURE.md#agentrun-lifecycle)
- [`journeys/editorial-review-approval.md`](./editorial-review-approval.md) —
  operator approval branch
- [`journeys/citation-drift-resolution.md`](./citation-drift-resolution.md) —
  Isis hash chain provenance inspection
- [`journeys/sophia-grounded-answer.md`](./sophia-grounded-answer.md) —
  retrieval-augmented composition path used by drafting stages
- [`journeys/crisis-aware-tone-policy.md`](./crisis-aware-tone-policy.md) —
  Lilith pre-check directive shape
- Pipeline registry source of truth:
  `libs/oshun/agentic-studio/src/pipelines/v1-pipelines.ts`
- Grant resolver: `libs/oshun/agent-pipelines/src/grants/resolver.ts`
- AgentRun contract: `libs/contracts/src/common/agent-run.ts`
- Studio composition bridges: `WALKTHROUGH/studio/domain-bridges/isis/`

## Pipeline variants

Customer entry-point links live in the earlier "Per-view files touched" section;
this table holds the registry deltas and states the current UI boundary
explicitly.

| Pipeline id                    | Current trigger state                                              | Output · final approval · tier                                                     |
| ------------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `veritas.weekly_briefing_pack` | Creator-triggered aggregation; no dedicated browser surface        | `veritas.briefing-pack`<br>`editor.review`<br>`creator`                            |
| `veritas.story_drafting`       | Operator queue on `/operator/studio`; no customer invocation       | `veritas.story-draft`<br>`editorial.inbox.handoff`<br>`platform-operator`          |
| `metis.course_from_byom`       | Declared for `/metis/byom`; dedicated browser adapter remains open | `metis.course`<br>`themis.prescreen` + teacher<br>`customer` (tenant-policed)      |
| `tara.seasonal_program`        | Operator schedule on `/operator/studio`; no customer trigger       | `tara.ritual-program`<br>lineage confirm + `editor.review`<br>`platform-operator`  |
| `nyx.event_explainer_set`      | Monthly cron / Nyx-desk trigger declared; adapter remains open     | `nyx.explainer-set`<br>`nyx.desk.review`<br>`tenant-operator`                      |
| `arete.weekly_review_draft`    | Customer `Run Now` is wired; weekly cron/push is separate infra    | `arete.weekly-review`<br>`user.confirm.before.publish`<br>`customer`               |
| `nisaba.edition_study_guide`   | Nisaba trigger declared; customer/scholar adapters remain open     | `nisaba.study-guide`<br>`scholar.review`<br>`customer` draft → scholar publication |

## Open questions / known gaps

- [x] A unified customer lifecycle ships at `POST/GET /v1/agentic/runs`, with
      approve, discard, control, common-ground, Lilith-override, and Yemaya
      takeover routes; one-shot guarded execution ships at
      `POST /v1/agentic/runs/execute`
- [ ] Wire and document the six registered variants that do not yet have a
      dedicated browser trigger equivalent to Arete's `Run Now` surface
- [ ] Centralize per-pipeline push-notification copy (currently pipeline-local)
- [ ] Snapshot per-pipeline `expectedHandoffDepth` / `totalBudgetCap` thresholds
      so SLA breaches in the deviation report tie back to alerts
- [ ] Confirm the `Run Now` affordance copy per surface (some may say `Generate`
      or `Draft`)
- [ ] Verify `metis.course_from_byom` tenant-teacher gate when the tenant has no
      seated teacher (fail-closed vs. soft fallback)
- [ ] Confirm idempotency keys on cron triggers prevent double-dispatch
- [ ] Capture the deferred-notification UX when quiet hours overlap completion
