# Upstream dual-coach port and offline deployment-candidate plan

## Summary
Port the *behavioral contract*, not the obsolete 36K-line snapshot, from `4305027f6 → d9e03e938 → 0dc0f228d` onto the pinned public base `origin/main` `41a07f5b8`. Produce a newly based, reviewable branch and replacement PR; keep PR #74072 and every existing worktree untouched until the replacement is proven. The candidate supports the private Profile API at `57aaf75` only through typed runtime contracts and sanitized fixtures. No profile data, credentials, live Telegram/provider invocation, raw-store write, customer activation, or delivery is part of this work.

Repository evidence: the old branch is rooted at `b88d0007c` and has local unrelated modifications/untracked files; the requested commits are three commits atop it. `4305027f6` adds 18 files / 35,627 lines and its old `gateway/platforms/telegram.py` was renamed upstream (61% similarity) to `plugins/platforms/telegram/adapter.py`. The later commits modify nutrition/Telegram lifecycle behavior. The profile’s `57aaf75` adds typed continuity, weekly-review source, and customer-safe rendering APIs. Current public `pyproject.toml` packages both `cron` and `plugins`, and the current Telegram group-gating test imports the plugin adapter. The prior clean cherry-pick conflict evidence therefore confirms an API port is required, not a blind replay.

## Principles
1. **Isolation and immutability first.** Route and authorize only on exact registered customer/owner triples; keep canonical customer lifecycle records append-only, with correction by a new superseding event rather than mutation.
2. **Human approval is a hard capability boundary.** AI may create a review draft only; a latest immutable child revision needs its own approval and no path may auto-send.
3. **At-most-once over apparent liveness.** Reserve before provider/publication effects; any consumed/claimed ambiguous outcome is terminal `delivery_unknown` and is never retried.
4. **Pinned content is the delivered content.** The exact approved customer preview/body bytes and their digest must be revalidated through card, approval, reservation, and provider invocation; never reconstruct text at send time.
5. **Fail closed and keep public code public.** Missing/invalid typed profile APIs, consent, ownership, policy/epoch pin, ledger, configuration, or activation rejects safely; no private profile source, profile data, identifiers, secrets, or executable live runbook material enters Hermes.

## Intent Diff
| Area | Old snapshot intent | Ported candidate intent |
|---|---|---|
| Gateway integration | Large legacy `gateway/platforms/telegram.py` implementation | Map only dual-coach ingress/card/typed lifecycle hooks into current `plugins/platforms/telegram/adapter.py` registration and adapter seams. |
| Nutrition/physique domain | Broad foundational drop including diagnostics/humanizer/scheduler helpers | Retain only code demonstrably required for the stated dual-coach contract; delete/reject generated, duplicate, dead, diagnostic-only, or obsolete compatibility architecture. |
| Profile coupling | Dynamic imports from local `checkin_cli` runtime | Explicit narrow compatibility boundary against Profile `57aaf75`; imports/type validation fail closed and tests use sanitized typed fakes. |
| Delivery | Review-to-delivery lifecycle | Preserve reservation-first, immutable receipt/audit lifecycle; default and candidate delivery flags remain false. |
| Pull request | Dirty, stale #74072 | New branch based exactly on `41a07f5b8`, independently CI-clean and mergeable; old PR retained as rollback/reference until replacement acceptance. |

## Decision Drivers
1. **Safety invariants are non-negotiable:** exact customer isolation, append-only history, no AI auto-send, exact body pins, provider/publication at-most-once, preflight-vs-unknown separation, and immutable child reapproval.
2. **The upstream architecture moved:** current Telegram code is a bundled plugin adapter, while the original patch targets a legacy gateway path and conflicted in scheduler/adapter/group-gating. Correctness requires API mapping and focused reimplementation rather than conflict-marker resolution.
3. **Public/private boundary and deployability:** Hermes must compile/package without private data while remaining compatible with the private Profile API pinned at `57aaf75`; a candidate is valuable only if it stops before Gate-D/live authority.

## Options
### Option A — New, clean port branch and replacement PR (recommended)
Create a new branch from pinned `41a07f5b8`, port selected behavior in small coherent commits, and open a replacement PR that links #74072. Leave #74072 untouched until replacement CI/review acceptance.

- **Pros:** preserves the old PR and original dirty branch for forensics/rollback; produces an auditable diff against current upstream; no force push; makes each mapped API/rejection explicit; naturally avoids unrelated local changes.
- **Cons:** review discussion/history does not remain on #74072; requires a new PR and explicit closure/supersession step.

### Option B — Rebase/force-update the existing PR branch
Build and validate the new clean branch first, then force-with-lease the existing PR head to its exact reviewed SHA.

- **Pros:** preserves PR number, subscribers, and some discussion continuity.
- **Cons:** rewrites a dirty/stale review surface, risks losing reviewer references and obscuring the 36K-line replacement; requires branch-owner approval and an exact remote lease; a failed force push creates unnecessary coordination risk.

### Option C — Cherry-pick the three commits then resolve conflicts
- **Pros:** superficially preserves original commit provenance.
- **Cons:** known conflicts and the legacy-to-plugin migration make it prone to retaining generated/obsolete architecture; the first commit’s 35K additions hide behavioral review; it is not a safe way to establish public/private boundaries.

**Recommendation:** Option A. Use Option B only after Option A has a green immutable candidate head, the PR owner explicitly chooses continuity over review clarity, and `--force-with-lease` names the observed remote SHA. Do not use Option C as the implementation path; a disposable scratch cherry-pick may be used only to locate semantic hunks.

## In scope / out of scope
**In scope**
- Fresh, current-upstream port of the three commits’ required dual-coach behavior.
- Explicit source/API mapping for the Telegram plugin, scheduler, nutrition lifecycle, physique check-in, focused tests, and runtime integration.
- Typed compatibility validation against private Profile commit `57aaf75` without copying its source/data.
- A mergeable replacement PR and an offline-only deployment candidate with immutable evidence.

**Out of scope**
- Copying `checkin_cli`, private profile files/data, profile configuration, credentials, Telegram IDs, consent records, or runbook executable steps into the public repository.
- Live Telegram/provider calls, test accounts/topics/bots, real customer registration/activation/delivery, raw storage/registry edits, Gate-D rehearsal, or rollout approval.
- Stashing, reverting, committing, cleaning, or otherwise changing the unrelated dirty worktree.
- Broad upstream cleanup/reformatting, unrelated scheduler refactors, changing generic Telegram semantics, or treating known contaminated legacy combined fixtures as proof.

## File-level changes and API mapping
Treat this as a requirements map; the executor must reconfirm current symbols after creating the isolated worktree.

| Source area | Current target / action | Required mapping and exclusion |
|---|---|---|
| `gateway/platforms/telegram.py` (old) | `plugins/platforms/telegram/adapter.py` | Port dual-coach interception before generic/message/model paths and through the plugin’s existing `TelegramAdapter`/registration seams. Preserve normal plugin wiring, adapter factory, and current callback authorization. Do not restore a legacy gateway adapter or duplicate plugin registration. |
| `tests/gateway/test_telegram_group_gating.py` (old) | current same test path, importing plugin adapter | Add only dual-coach exact-triple/group/topic gating tests; preserve existing broad group-observation tests and current test helpers. |
| `gateway/platforms/nutrition_coaching.py` | new/ported public gateway domain module only if no upstream equivalent exists | Map typed Profile calls: `CustomerActionContinuity`, `CustomerActionOutcome`, `build_registered_daily_customer_projection`, `CustomerWeeklyReviewSource`, `build_customer_weekly_review_source`, registry loader, verified risk policy, and activation/reconciliation API. Make import/shape/version failure a safe unavailable/rejected result. Do not vendor Profile implementations. |
| `gateway/platforms/physique_checkin.py`, bindings/config/prompts | narrowly ported gateway boundary modules | Preserve exact address routing and typed event/callback handoff; keep prompts/config generic and secret-free. Drop any unused generated material. |
| `cron/scheduler.py` and `cron/physique_inline_card.py` | current scheduler and a small new helper only if current scheduler has an appropriate callback seam | Integrate only profile-gated, disabled-by-default bounded card scheduling. It must not create activation/delivery state, bypass the typed adapter, or send without reservation/authority. Reject the helper entirely if no contract requirement remains after mapping. |
| `diagnostic_isolation.py`, `korean_humanizer.py`, associated tests | include only after a dependency trace proves necessity | The first commit added these large modules. Do not port by association. If retained, isolate pure deterministic behavior and prove it neither loads private data nor changes delivery semantics; otherwise omit. |
| focused tests | `tests/gateway/test_adaptive_nutrition.py`, `test_nutrition_coaching.py`, `test_telegram_physique_checkin.py`, group-gating tests, `tests/cron/test_physique_inline_card.py` | Rebuild tests around current seams and sanitized fakes. Keep new tests small, contract-named, and independent; do not rely on the known contaminated combined suite. |
| defaults/docs/package metadata | existing public config/sample/runtime guidance only when affected | Add disabled-by-default public guidance if runtime discovery/configuration needs it. Verify package discovery includes new modules; no profile defaults, identifiers, or runbook procedures. |

### Required Profile `57aaf75` compatibility matrix
Before implementation, generate a private, non-exported matrix with exact symbol, signature, return shape, failure behavior, caller, and fixture for: `CustomerActionContinuity`, `CustomerActionOutcome`, `AdaptiveEventStore` continuity append/read methods, `build_registered_daily_customer_projection`, `CustomerWeeklyReviewSource.render_customer_body`, `build_customer_weekly_review_source`, registered runtime registry loading, verified risk policy, activation validation, and reconciliation. The port must call only the pinned typed surface or a deliberately tiny adapter protocol that is tested against it. A missing symbol, wrong type, duplicate runtime/customer match, invalid preview, or registry/authority error must not fall back to raw JSON, stringly calls, default customer selection, or delivery.

## Sequencing and dependencies
1. **Freeze facts and create an isolated branch.** Record `41a07f5b8`, the three source commits, `b88d0007c`, PR #74072 state, and Profile `57aaf75`. Verify the original Hermes worktree remains dirty and do not touch it. Confirm public source has no private profile data/secrets. Create a sibling detached worktree exactly at `41a07f5b8`, inspect it as clean, then create `port/dual-coach-41a07f5b8` there. Do not work in the original worktree and do not use stash/reset/clean.
2. **Inventory behavior before code.** Convert each source hunk/test into an invariant→current seam→Profile API→test table. Use a disposable scratch worktree only to inspect `git cherry-pick -n`/conflict hunks; abort/remove it after recording mappings. Compare source against `41a07f5b8`, including the known `gateway/platforms/telegram.py` → plugin adapter rename, and classify every added foundational file as required, replaceable, or omitted.
3. **Port foundation and typed boundary in reviewable commits.** First add the smallest public models/protocols and fail-closed runtime authority/registration/preview validation. Keep all flags false by default. Establish append-only event/ledger adapter calls and exact identity validation before UI/cards. Commit with decision trailers that state constraints, rejected fallbacks, test scope, and the Profile API pin.
4. **Port review, immutable revision, and exact preview flow.** Wire customer/owner routing, draft/revision/approval cards, weekly source flow, and exact body pins into current Telegram plugin callbacks. An edit creates a fresh child; it cannot inherit approval/capability/reservation from its parent. A stale card, changed owner/policy/epoch/registry/consent, or body/digest mismatch is rejected before a provider call.
5. **Port delivery/scheduler state machine only after approval flow passes.** Implement reservation-first lifecycle and current scheduler integration. Classify a typed preflight failure as provider-zero/retryable only before provider invocation. Once claim/consume occurs, generic transport failure, timeout, restart ambiguity, or receipt/audit failure becomes terminal no-resend unknown/audit-pending and reconciliation performs zero provider calls. Map static review publication to the same at-most-once semantics.
6. **Rebuild focused verification and audit the public boundary.** Add unit/integration/offline e2e tests below, run only in the isolated worktree, validate packaging/lint/type checks per current project tooling, scan the candidate diff for secrets/private paths, and inspect every changed line. Fix source issues, not tests or suppressions.
7. **Publish replacement safely.** Push the new branch, open replacement PR referencing #74072 and the three source commits, include the invariant/API mapping and proof artifacts, and require mergeable state plus CI. Keep #74072 open/read-only until the replacement has passed review/CI; then close it as superseded. Do not force-update its branch by default.
8. **Produce and stop at the offline candidate gate.** Build the candidate from the replacement SHA with Profile compatibility evidence and an all-false delivery config. Run read-only/local preflight only. Record the canonical runbook pointer/hash privately, then stop before human-only Gate-D, secrets/accounts, customer activation, any provider call, delivery, or rollout approval.

### Exact clean-worktree/branch strategy
The executor uses commands equivalent to the following only in a new sibling directory, never the dirty worktree:

```text
git fetch --prune origin
git rev-parse 41a07f5b8
git worktree add --detach /home/cube/projects/richard/hermes-agent-dualcoach-port-41a07f5b8 41a07f5b8
# inside the new worktree: verify `git status --porcelain` is empty
git switch -c port/dual-coach-41a07f5b8
```

If `origin/main` has advanced after planning, retain the requested base commit for this pass and record the drift; do not silently retarget. If release policy requires the newest tip, restart the port from the new verified tip with a new mapping/review, because the known 6,916-commit divergence makes a rebase nontrivial. The original `feature/dual-coach-lifecycle` worktree—including its modified BlueBubbles/Photon/tools files and untracked `.gjc`/MacBook files—must remain byte-for-byte untouched. No stash, `reset`, `restore`, `clean`, checkout, commit, or test is run there.

## Conflict-resolution gate
For each conflict or semantic mismatch, resolve in this order:
1. Identify its source invariant and the current owner API; read the current adapter/scheduler/tests before selecting code.
2. Map legacy path to current path (notably legacy Telegram gateway to bundled plugin adapter) and prefer current plugin lifecycle/authorization conventions.
3. Preserve stricter behavior when safety semantics differ. Do not make uncertain delivery retryable, relax exact triples, reuse approval, or re-render a pinned body merely to retain a source hunk.
4. Reimplement the smallest required behavior with focused tests; remove obsolete source scaffolding rather than leaving aliases, duplicate handlers, or compatibility fallbacks.
5. Require a named reviewer/architect gate for any changed public/Profile signature, lifecycle state transition, storage schema, provider invocation boundary, callback authorization path, or scheduler recovery path.

Stop the port and escalate rather than guessing if the Profile pin has a missing/incompatible typed API, current plugin hooks cannot intercept before generic dispatch, a required behavior needs raw storage, or an upstream API change makes exact identity/body pins unrepresentable.

## Test and observability plan
No tests are executed in this planning pass. The implementation pass runs the following in the clean worktree only.

### Unit tests
- **Isolation/routing:** exact customer, trainer, configured review, and canonical owner triples; same chat with wrong topic/user; wrong topic with right user; wrong customer key; generic-path bypass; all non-exact cases fail closed with no draft/event/provider action.
- **Append-only and authority:** transitions append immutable rows; correction/child revision has `supersedes`; no in-place mutation; stale owner/policy/registry/consent/epoch/activation/capability is rejected.
- **Human review/reapproval:** AI generates review-only artifact; no callback can auto-send; parent approval cannot send an edited child; latest child requires new explicit approval; old card/capability fails.
- **Exact body pins:** byte-for-byte preview/body plus digest at creation, card redisplay, approval, reservation, and transport; whitespace/Unicode/body changes and re-render mismatch reject before invocation.
- **Delivery classification:** typed preflight rejection before invocation has zero calls and may be retried after correction; generic exception/timeout after claim or consume becomes unknown with exactly one/max allowed attempt and retry adds zero calls; receipt-present/audit-pending reconciliation adds audit only and zero calls.
- **Publication/scheduler:** duplicate publication and duplicate callback return terminal duplicate/no extra provider call; unknown/restart/torn/corrupt/fence-not-ready rows send nothing; disabled flag sends nothing.
- **Private boundary:** sanitized fake implementations conform to the Profile compatibility protocol; missing/wrong type/duplicate runtime throws unavailable/rejected, never raw-file fallback.

### Integration tests
- Construct an isolated temporary profile fixture with distinct customer/trainer/reviewer triples, fake typed registry/authority, append-only in-memory/file temp ledgers, deterministic KST clock, and a recording fake transport. Assert customer state never appears in another customer card/ledger.
- Exercise full local flow: check-in/source → proposal → exact preview → immutable approval → reservation → one fake provider receipt → delivered/audit, plus duplicate callback/restart, unknown, receipt/audit reconciliation, owner/policy rotation, and delivery revoke race.
- Exercise Telegram plugin ingress/callback ordering through current `TelegramAdapter` test helpers: review space is reserved before generic routing for every relevant update type; unauthorized/wrong-topic callbacks reach neither generic/model nor dual-coach state.
- Exercise scheduler startup/recovery with disabled flags and fake clock only; assert no network client/provider method is invoked.
- Run the focused suites first (adaptive, nutrition, Telegram physique/group gating, inline card) and keep their fixtures hermetic. Treat the known legacy combined fixture-contamination suite as a diagnostic only; do not use it for release proof until contamination is isolated/fixed.

### Offline e2e and candidate validation
- Launch only a local fake adapter/profile fixture with all activation and delivery flags false. Assert preflight returns bounded booleans/counts/digests/epoch and performs no writes, creates no account/artifact/customer/ledger, and makes zero provider calls.
- Package/install smoke test the public candidate in an isolated environment with a synthetic Profile API fixture; ensure missing private package fails closed rather than importing/copying it.
- Assert default/sample configuration has every delivery/activation flag false, no bot tokens/chat IDs/customer IDs, and no public reference to private local paths beyond an allowed non-executable documentation pointer when required.

### Observability requirements
Emit structured/redacted local logs/metrics for: correlation/revision/digest (hashed or bounded), exact-triple gate outcome, capability/epoch/policy pin outcome, reservation state, provider invocation count, receipt/audit state, preflight vs unknown classification, and recovery fence decision. Never emit body text, profile paths, credentials, customer identifiers, or provider payloads. Candidate evidence records aggregate counts and digests only.

## Verification Plan
1. Confirm base/candidate ancestry and branch diff are limited to intentional files; run whitespace/lint/type/package checks scoped to new changed code according to current project tooling.
2. Run focused unit and integration suites listed above, then relevant unaffected Telegram/plugin/scheduler regression suites. Preserve raw test logs as private CI artifacts; publish only safe summaries.
3. Run offline e2e with recording transport and assert provider/publication calls equal 0 where flags/preflight require it, 1 only in fake approved simulated delivery scenarios, and no retry after unknown/receipt states.
4. Run a public secret/privacy scan over the candidate diff and full added files for tokens, private profile paths, customer/Telegram identifiers, fixture data, and executable Gate-D instructions. Review false positives manually; do not waive actual findings.
5. Verify PR metadata: base SHA/current intended base, replacement branch head, CI conclusion, mergeable state, review approvals, and no forced rewrite of #74072. Verify candidate manifest commits/profile API hash/flags all false.

## Acceptance criteria
- A new branch based on exactly `41a07f5b8` is independently mergeable and contains no unrelated dirty-worktree changes; #74072 is preserved until replacement acceptance.
- Ported behavior uses current Telegram plugin integration and current scheduler seams; it does not restore the legacy adapter path or blindly carry foundational generated/obsolete modules.
- Public Hermes contains no private Profile source/data/secrets; private `57aaf75` compatibility is proven via typed interface tests and an API matrix.
- Exact registered triples isolate all ingress, lifecycle, and audit operations; all wrong/ambiguous identity cases fail closed and bypass generic/model paths.
- Lifecycle records are append-only; edits create immutable children, invalidate parent approval/capabilities, and require child reapproval.
- AI content cannot auto-send. The same approved preview/body bytes/digest remain pinned at card, approval, reservation, and fake transport.
- Provider and review publication are at-most-once: duplicate, restart, unknown, receipt-present, and audit-pending paths issue no duplicate call. Only verified typed preflight failures before invocation are retryable; generic ambiguity is terminal no-resend.
- Candidate defaults/preflight keep all delivery and activation flags false, perform no mutation/provider call, and stop before Gate-D/live/human-only actions.

## Proof artifacts
- Base/branch ancestry record, clean-worktree status before/after, changed-file allowlist, and conflict/API decision table.
- Private compatibility matrix referencing Profile commit `57aaf75` by commit/symbol/signature only; no copied content.
- Focused test/CI summaries with test names, outcomes, coverage of each invariant, recording-transport call counts, and failure-path assertions.
- Redacted observability sample showing classification/pins/reservation/audit without customer or message data.
- Public privacy/secret scan report and manual review sign-off.
- Replacement PR URL/head SHA/mergeable CI evidence and #74072 supersession link.
- Offline candidate manifest: Hermes SHA, Profile API SHA `57aaf75`, canonical runbook contract hash pointer, package checksum, all delivery/activation flags false, preflight digest/count result, and explicit `manual Gate-D pending / rollout approval pending` statement.

## Escalation/Risk Gate
Do not proceed past the relevant gate without resolution:
- **Architecture gate:** current plugin or scheduler lacks a safe semantic seam; architect must choose an additive current-architecture integration before code is written.
- **Profile contract gate:** `57aaf75` cannot satisfy the narrow typed compatibility matrix; coordinate a private Profile change or a public protocol revision—never copy/private-vendor code.
- **Safety gate:** any test shows cross-customer data, mutated history, inherited child approval, changed pinned bytes, provider count >1, or retry after unknown; block PR/candidate and fix at source.
- **Privacy gate:** candidate contains secret/profile/private data or executable human-only procedure; remove it and rerun scan.
- **Release gate:** live credential/account/customer/Gate-D/rollout work is requested; stop. These are human-only and outside this plan.

## Pre-mortem: likely failure scenarios
1. **Legacy gateway code is merged beside the plugin adapter.** Early sign: duplicate Telegram handlers/imports or tests still import `gateway.platforms.telegram`; impact is inconsistent callback ordering and authorization bypass. **Mitigation:** make the rename mapping a required review checklist item; enforce plugin-only imports and adapter-order integration tests.
2. **A large foundational file hides generated/obsolete behavior.** Early sign: 10K+ line additions without a direct invariant/test owner, duplicate services, or references to old APIs. **Mitigation:** per-file required/replaceable/omit ledger; require dependency trace and named tests before retaining diagnostic/humanizer/scheduler additions; prefer small reimplementation.
3. **Profile drift is concealed by permissive dynamic imports/fakes.** Early sign: `getattr` defaults, fallback runtime selection, broad `except`, or tests that do not instantiate the `57aaf75` shapes. **Mitigation:** signature matrix and strict protocol/type validation; use real private pinned checkout only in private compatibility CI; missing APIs fail closed.
4. **Ambiguous provider outcome is classified as retryable.** Early sign: retry code observes a missing marker/exception and calls transport again; provider counter rises above one. **Mitigation:** explicit preflight-before-invocation state and terminal unknown tests across timeout/restart/exception; reconciliation is receipt/audit-only.
5. **An edited child sends under parent approval or re-rendered body.** Early sign: parent revision/digest/capability accepted after edit or body differs at transport. **Mitigation:** store parent/child and immutable body digest in tests; invalidate/reissue approval and capability; compare exact bytes at every boundary.
6. **Replacement PR loses rollback or dirty local work.** Early sign: force push proposed before independent green branch, or commands target old worktree. **Mitigation:** sibling worktree + new branch/PR default; no stash/reset/clean; retain #74072 until new branch evidence is complete.

## Risks and mitigations
| Risk | Mitigation |
|---|---|
| 6,916 upstream commits of divergence | Pin base, rebuild against current APIs, run current focused regressions, and record API mapping rather than rebasing old history. |
| Existing PR dirty / 36,770 additions | New replacement PR with small commits and file allowlist; keep old PR as rollback. |
| Known cherry-pick conflicts | Use scratch conflict output as discovery only; resolve by behavior/current ownership, never conflict-marker precedence. |
| Combined fixture contamination | Hermetic focused fixtures and isolated local e2e; legacy combined suite is non-release diagnostic evidence. |
| Human/live boundary breach | All flags false, recording transport, preflight-only candidate; explicit stop gate before Gate-D/activation/provider actions. |
| Public/private leakage | Protocol-only coupling, sanitized fixtures, diff scan/manual review, private artifacts kept outside public repository. |

## RALPLAN-DR summary
**DR-1 — Replace rather than rebase the dirty PR.** Adopt a fresh branch/PR from `41a07f5b8`; preserve #74072 as rollback evidence. The upstream/plugin migration and large legacy patch make review clarity and reversibility more valuable than PR-number continuity.

**DR-2 — Port safety invariants through current architecture, not commit text.** The legacy Telegram gateway path has moved to `plugins/platforms/telegram/adapter.py`; scheduler and group-gating conflicts prove that direct cherry-picking is unsafe. Source commits are behavioral evidence, not an architectural template.

**DR-3 — Keep Profile integration typed, pinned, and private.** Support Profile `57aaf75` with a narrow compatibility matrix/protocol and fail-closed behavior. Never publicize or vendor private source/data.

**DR-4 — Candidate is offline and non-authorizing.** The deployable artifact demonstrates package/config/preflight compatibility with every delivery/activation flag false. It is explicitly not Gate-D, a live Telegram rehearsal, customer activation, delivery, or rollout approval.

## ADR-ready decision rationale
**Title:** Port dual-coach behavior onto the Telegram plugin with a fresh replacement branch and a typed private-profile boundary.

**Status:** Proposed for implementation.

**Context:** The source commits sit on `b88d0007c`, 6,916 commits behind `41a07f5b8`; the legacy Telegram module was migrated to the bundled plugin adapter, and a clean cherry-pick already conflicted in scheduler, adapter, and group-gating tests. The source patch is broad, while the private Profile at `57aaf75` provides required runtime types that cannot enter public Hermes. Delivery safety and customer isolation are release-critical.

**Decision:** Build a new branch at `41a07f5b8`, map selected behavior into current public seams, use strict typed Profile compatibility, and replace #74072 with a new mergeable PR. Preserve append-only, exact-triple, immutable-approval/body-pin, and at-most-once semantics. Produce only an offline candidate with disabled delivery.

**Consequences:** Review gains a small, current-architecture diff and safe rollback; PR discussion is split and implementation requires an explicit API matrix. No live readiness claim is made; human-only Gate-D and rollout approval remain pending.

## Handoff
Use an **executor** for the isolated implementation and focused tests; request an **architect** review at the adapter/scheduler/Profile-contract gates; use a **critic** for invariant and test-plan review before PR publication. Do not use an autonomous deployment/team lane for live boundaries. A release owner/human performs only the separately approved Gate-D and rollout actions after this plan’s offline candidate is accepted.
