# Revision plan — safe current-upstream dual-coach port and offline candidate (topology-correct)

## Summary
For the nontechnical owner: PR #74072 must not be deployed as-is. Its head `0dc0f228d` is dirty, non-mergeable, human-labelled `invalid`, and its three commits sit on `b88d0007c`, **6,916 commits behind** verified current upstream base `41a07f5b8`. Its 36,770-line patch targets the removed legacy Telegram gateway, while current Hermes uses plugin architecture. Deploying it can bypass current routing, authorization, and recovery conventions and include unrelated dirty-worktree material. A fresh, reviewed, offline-only semantic replacement is necessary; this is not live readiness.

This revision preserves the prior human gates, source-hunk ledger, safety invariants, collision protection, provenance, and offline boundary. It corrects two executable-contract gaps: the host must discover the disabled plugin through its exact allow-list key, and the candidate must carry distinct host/plugin artifacts, commands, identities, PR outcomes, and rollback rules for the selected topology.

## Intent Diff
| Concern | Unsafe legacy premise | Decision |
|---|---|---|
| Placement | Profile-specific behavior embedded in legacy/bundled gateway | Default A is a separately distributed private plugin; B adds only approved generic reusable Hermes hooks; C is prohibited without a named written exception. |
| History | Rebase/cherry-pick/repair #74072 | New immutable work only from `41a07f5b8`; #74072 remains untouched until the applicable human disposition gate. |
| Behavior | Copy a large source snapshot | Semantically reimplement exact-triple isolation, append-only revisions, child reapproval, body-digest pins, reservation-first/at-most-once, and no-send-on-unknown. |
| Offline candidate | Implied delivery readiness | Local preflight/install smoke only. Host discovery is opt-in, but every behavior/delivery flag is false. |
| Private dependency | Dynamic Profile/local-source coupling | Typed `57aaf75` Profile protocol with fail-closed errors; no private source, identity, path, secret, data, or executable live runbook in Hermes. |

## Decision Drivers
1. Hermes requires edge capability through plugins/skills before core; plugins must not special-case core. A missing required seam may justify only a generic capability surface.
2. `hermes_cli/plugins.py` confirms standalone/user/entry-point plugins are opt-in: `plugins.enabled` is an allow-list of `PluginManifest.key`, and discovery skips a plugin not present. For a top-level standalone package the key is its manifest `name`; for an entry point it is its entry-point name. The private plugin’s immutable registry key is therefore **`dual_coach`** in both its `plugin.yaml` (`name: dual_coach`) and, if entry-point packaged, `hermes_agent.plugins` entry-point name. The host config must use that exact string, not `dual-coach`, a directory alias, or a nested behavior flag.
3. Topic-59 reservation precedes every Telegram update type. Configured review triple and refreshed canonical-owner triple are distinct. Every mutation revalidates owner/config/registry/consent/activation/source/artifact/epoch; unknown, receipt-present, and audit-pending never resend.
4. Generic scheduler due/claim/execution remains in Hermes. Domain reservation and receipt ledger remain in the plugin; neither substitutes for the other.
5. The `invalid` label is a premise warning. Only the invalid-label maintainer plus Hermes architecture maintainer can select topology and public allow-list before implementation.

## Options
### A — Existing public surfaces; private standalone plugin (default)
A separately versioned private distribution owns all Profile-aware dual-coach behavior, operator console, customer/trainer flows, durable domain ledger, typed Profile adapter, and offline CLI. It is installed as a user plugin at `$HERMES_HOME/plugins/dual_coach/` or as a `hermes_agent.plugins` entry point whose name is `dual_coach`. It uses existing generic registration, Telegram/platform, callback/session, and scheduler surfaces only.

GO requires a spike proving those surfaces reserve every needed ingress before generic dispatch and carry typed callback/session and scheduler invocation without core alteration or monkeypatch. Its compatibility host is immutable `HERMES_BASE=41a07f5b8`; `PLUGIN_SHA` is the private checkout revision. There is **no Hermes replacement PR** under A. After human acceptance of the private candidate, the named humans record #74072’s disposition (retain, close as superseded by private delivery, or another explicit disposition); no disposition is implied by a nonexistent upstream replacement.

### B — Generic upstream hooks plus private standalone consumer
Only if A demonstrably lacks a required invariant and named maintainers approve the public allow-list: Hermes adds generic `TelegramIngressHook.reserve_update`, `TelegramCallbackHook.handle_callback`, and `ScheduledJobHook.launch` equivalents. They run before contact, edited-message, channel-post, edited-channel-post, text/command, location/venue, every media type, generic/model dispatch, and generic callback namespaces. `RESERVED` consumes, `PASS` continues, and `REJECTED` consumes with only a bounded safe notice. The scheduler hook runs only after Hermes due/claim ownership and cannot mark, advance, or claim generic jobs.

No Profile, dual-coach, nutrition, Topic-59, Korean, customer, or delivery-policy names enter Hermes. The standalone consumer retains domain routing and calls its distinct `DualCoachReservationLedger.reserve()` before any provider effect. Generic claim is not domain reservation and domain reservation cannot mutate generic cron state. The replacement Hermes PR contains only approved generic allow-list paths.

### C — Bundled Profile-aware Hermes behavior
Bundled adapter/scheduler behavior is rejected. It becomes eligible only after a written exception signed by the named Hermes maintainer who owns/applied #74072’s `invalid` disposition **and** the named architecture reviewer. The exception must explain why A and B cannot satisfy the invariant, name public files/APIs and maintenance owner, approve the exact allow-list, and authorize a bundled Hermes source/PR. Silence, ambiguity, or a one-person approval is no-go.

## In scope / out of scope
**In scope:** one human-approved A/B/C semantic port; signed source-hunk appendix; typed private Profile boundary; topology-specific artifact/evidence/rollback procedure; hermetic offline preflight; provenance; current-base generic PR only where B/C is authorized.

**Out of scope:** mutating #74072 before its human disposition; force push/update, deletion, merge, or remote cleanup; private Profile source/data/paths/identities; credentials, bots, topics, accounts, consent, customer registration/activation; raw registry/EventStore edits; live Telegram/provider calls; Gate-D; rollout; broad scheduler refactor; bundled C absent its exception.

## File-level changes
| Topology | Hermes root and allowed changes | Private plugin root and required changes |
|---|---|---|
| A | `HERMES_ROOT=/home/cube/projects/richard/hermes-agent` at `HERMES_BASE=41a07f5b8`; no Hermes source, test, metadata, PR, or wheel change. It is a compatibility install input only. | Named private `PLUGIN_ROOT` at immutable `PLUGIN_SHA`; `plugin.yaml` / entry point key exactly `dual_coach`, plugin CLI `hermes dual-coach preflight`, disabled configuration schema, domain modules, typed adapter, tests, and wheel. |
| B | Isolated clean `HERMES_HOOK_ROOT` on `HERMES_HOOK_SHA` rooted at `41a07f5b8`; only `gateway/builtin_hooks/telegram.py`, `cron/hooks.py`, registration points in `plugins/platforms/telegram/adapter.py` and `cron/scheduler.py`, generic tests, generic discovery schema/docs, and package metadata only if necessary. | Separate `PLUGIN_ROOT` at `PLUGIN_SHA` with the same private artifacts as A. No Profile-aware code in host. |
| C | Separate clean authorized Hermes worktree/PR only after exception; all files limited to the exception’s named allow-list. | Only any separately approved consumer/supporting artifact; never use C to evade the private boundary. |

The signed hunk appendix remains a precondition. It machine-enumerates every hunk in `git diff --find-renames b88d0007c..0dc0f228d`, source range, disposition, invariant, exact target symbol, owner, public/private location, config default, Profile contract/error, ingress ordering, and test. Omitted hunks remain omitted. Replace old Telegram/group-gating behavior in plugin ingress/callback (and generic hook only in B); replace nutrition/operator/review/approval/delivery and physique contracts in plugin; replace scheduler/card behavior with plugin launch/ledger (B only supplies generic launch hook); omit diagnostic/humanizer unless signed dependency proves a pure generic need; omit generated, aliases, compatibility imports, prompts, dynamic imports, secrets, and private paths.

## Sequencing and dependencies
1. Freeze `41a07f5b8`, `4305027f6 → d9e03e938 → 0dc0f228d`, `b88d0007c`, Profile `57aaf75`, #74072 state, and original dirty-worktree fingerprint. Obtain the two named human approvals: invalid-label rationale, A/B/C selection, generic allow-list, whether a PR is wanted, and #74072 disposition authority.
2. Produce and have architect + invalid-label maintainer sign the full hunk appendix and its invariant/test mapping. Stop if a hunk needs a public exception outside the selected allow-list.
3. Create only collision-checked clean worktrees. From neutral context use `git -C /home/cube/projects/richard/hermes-agent`; never work in the dirty original, fetch/prune, stash, reset, clean, reuse, or test there. Record original branch/status/binary staged and unstaged diffs, their SHA-256 fingerprint, worktree list, and `41a07f5b8^{commit}`. Stop on existing `PORT`/`SCRATCH` paths, branch/ref, worktree record, shared-ref surprise, or unclean created worktree. Create detached worktrees, then branch only approved B/C host work; recompare original fingerprint before publication. Remove only recorded clean worktrees created by this run, identity-checked, never forced.
4. Implement the private plugin first for A; for B implement the approved generic host contract and then the independent consumer; C only after exception. Preserve exact ingress ordering, typed error rejection (`ProfileUnavailable`, `ProfileContractMismatch`, `AmbiguousRuntime`), canonical ownership refresh, capability/session binding, append-only revisions, digest pins, separate reservations, and zero generic fallback. Use source hunk IDs, original source SHAs, accurate `Co-authored-by: BEENZiN0 <224058983+BEENZiN0@users.noreply.github.com>` where applicable, and Lore provenance trailers.
5. Build, test, install, and evidence the selected topology using its exact roots/identities below. Critic re-review is required before any B/C PR open. Stop before every live boundary.

## Exact disabled discovery configuration and E2E
The test fixture and release candidate use a fresh temporary `HERMES_HOME`, not a developer home. The plugin’s installed top-level manifest/entry-point key is fixed as `dual_coach`. The exact config is:
```yaml
plugins:
  enabled:
    - dual_coach
  dual_coach:
    enabled: false
    ingress_enabled: false
    customer_ingress_enabled: false
    trainer_ingress_enabled: false
    operator_console_enabled: false
    scheduler_enabled: false
    activation_enabled: false
    delivery_enabled: false
```
`plugins.enabled` authorizes host discovery and CLI registration only; it is not a behavioral enablement. No omitted plugin behavior flag may default true, and preflight rejects a config with any behavior/delivery switch true. No new user-facing `HERMES_*` behavior variable is allowed.

For every selected topology, create an isolated venv, install the pinned host distribution plus the private wheel, install/resolve the wheel so Hermes discovers `dual_coach` from `$HERMES_HOME/plugins/dual_coach/` or the identically named entry point, set only the temporary `HERMES_HOME`, then run:
```text
hermes plugins list                 # prove dual_coach is discovered and enabled by allow-list
hermes dual-coach --help            # prove top-level CLI registration
hermes dual-coach preflight --config "$TMP_HOME/config.yaml" --artifact "$TMP/artifact.json" --json
```
The test must prove discovery fails/CLI is absent when the allow-list entry is removed, succeeds with the exact config above, and still records every behavior flag false. It uses a synthetic typed Profile fixture only. Before/after path/digest maps of temporary `HERMES_HOME` and artifact parent are identical except the named artifact; network, socket, provider, Telegram adapter, scheduler transport, and write counters are zero. Logs/artifact contain only bounded booleans/counts/digests/epoch; no body, ID, private path, token, credential, or provider payload. This isolated plugin-install + temporary-home discovery/preflight proof is mandatory even under A.

## Artifact, PR, acceptance, and rollback matrix
| Topology | Immutable identities and build roots | Commands and E2E inputs | PR/disposition | Acceptance and rollback |
|---|---|---|---|---|
| A | `HERMES_BASE=41a07f5b8`; `PLUGIN_SHA=$(git -C "$PLUGIN_ROOT" rev-parse HEAD)`; private wheel SHA-256. `PLUGIN_ROOT` is the named private checkout/package root, never `HERMES_ROOT`. | From `PLUGIN_ROOT`: `python -m pytest -q tests`; `ruff check` and `ty check` all changed plugin paths; `python -m build`; `sha256sum dist/*.whl`. Install pinned `HERMES_BASE` + exact plugin wheel into the temporary E2E venv and run the discovery/preflight contract. Do **not** invoke Hermes source wrapper or legacy paths such as absent `tests/gateway/test_adaptive_nutrition.py`. | No Hermes replacement PR or replacement `CANDIDATE_SHA`. After private human acceptance, named humans explicitly record #74072 retain/close/supersession disposition without claiming an upstream replacement. | Accept only plugin tests/build/privacy/redaction/write-set/discovery/preflight green and immutable compatibility tuple `(41a07f5b8, PLUGIN_SHA, PLUGIN_WHEEL_SHA256, Profile 57aaf75)`. On failure do not publish; retain local evidence and #74072. On later failure, revoke/remove only the identified plugin artifact from the candidate environment; do not alter host or #74072. |
| B | `HERMES_HOOK_SHA=$(git -C "$HERMES_HOOK_ROOT" rev-parse HEAD)` rooted at `41a07f5b8`, host build checksum `HERMES_WHEEL_SHA256`; separate `PLUGIN_SHA` and `PLUGIN_WHEEL_SHA256`, built only from `PLUGIN_ROOT`. These are two independent artifact checksums and two independent source revisions. | In `HERMES_HOOK_ROOT`, run `scripts/run_tests.sh` only for actually added generic-hook tests from the changed-file manifest, current `tests/gateway/test_telegram_group_gating.py`, relevant current generic cron regressions, then full `scripts/run_tests.sh`; run host `ruff`/`ty` on changed host paths and build host artifact from that root. In `PLUGIN_ROOT`, run `python -m pytest -q tests`, plugin `ruff`/`ty`, `python -m build`, and wheel SHA. Install both exact built artifacts for temporary-home discovery/preflight plus two synthetic consumer reserve/decline tests. | New replacement PR only for the approved generic Hermes allow-list, pinned to `HERMES_HOOK_SHA`; link source and private compatibility evidence but no private content. #74072 remains untouched pending explicit human disposition. | Accept only compatibility matrix green: host `HERMES_HOOK_SHA`/`HERMES_WHEEL_SHA256` × plugin `PLUGIN_SHA`/`PLUGIN_WHEEL_SHA256` × Profile `57aaf75`, with independent host/plugin suites and joint E2E green. If either artifact/CI/review fails, block/close only that replacement as PR owner chooses and create a new reviewed immutable pair; never force-update/delete/merge or alter #74072. |
| C | Named exception identifies `HERMES_BUNDLED_SHA` and any separately approved plugin SHA/wheel. | Run only exception-allowlisted changed-source tests plus required current host suite, host build/checksum, and the exact disabled discovery/preflight proof. | Bundled Hermes PR exists only under the two named written approvals. | Accept/rollback identities and PR action are exactly those named in the exception; absence means no implementation/publication. |

For all published work: no executor merges, deletes a remote branch, or force-updates. A wrong head stops review and is corrected with a fresh immutable branch/PR, never force push. Pre-push verification failure or original-fingerprint drift means no publication. Accepted-but-unmerged heads remain intact; any change is a new SHA/review. #74072 can only be closed by its authorized human after explicit selected-topology acceptance; closure never implies merge or live activation.

## Verification
- Plugin focused tests cover all Telegram update types and callbacks, wrong triple zero downstream/network/state, child reapproval, body digest/Unicode/whitespace pin, policy/owner/epoch rotation, generic-claim/domain-reservation separation, duplicate/restart/torn/corrupt/fence, preflight versus unknown, receipt/audit reconciliation, and disabled zero send.
- B additionally proves two synthetic generic consumers can independently reserve/pass/decline, reservation precedes all generic paths, scheduler hook cannot mutate generic state, and current group-gating/current cron regressions remain green. C uses its exception-defined host proof.
- All selected artifacts receive `git diff --check`, changed-file allow-list review, public secret/privacy scan, redacted raw-log retention, and exact source/artifact/config/profile SHA evidence. No xfail/skip/suppression masks a failure; new `ty` diagnostics require a narrow named-maintainer waiver.

## Verification Plan
1. Record base ancestry, source/hunk appendix, original fingerprint, topology gate, exact checkout roots, current SHAs, wheel SHA-256s, config digest, and compatibility matrix before testing.
2. Execute only the topology row’s commands from its named root. Under A no Hermes wrapper/source or nonexistent legacy target is required. Under B, wrapper/full-host testing is required because the host changes. Under C, host testing is conditional on the signed exception.
3. Execute the isolated install + temporary-`HERMES_HOME` discovery/CLI/preflight scenario exactly as configured above, with recording fakes and before/after write-set manifests. Assert zero network/provider/Telegram/scheduler calls and no forbidden serialization/log text.
4. Run fake approved-delivery simulation only in local fixtures: exactly one call after an explicit local fake authorization; duplicate, timeout/restart ambiguity, receipt-present, and audit-pending perform zero additional calls. No live provider or customer action occurs.
5. Capture private raw outputs and publish only redacted summaries. Reconcile artifact SHA-256s, PR head (where applicable), test/lint/type/build results, allow-list, and `manual Gate-D pending / rollout approval pending` in the offline manifest.

## Acceptance criteria
- The named invalid-label maintainer and architecture maintainer explicitly select A/B/C, resolve the `invalid` premise, approve the corresponding public allow-list, and issue C’s additional exception when C is selected.
- The signed appendix covers every source hunk and preserves stated ownership/config/Profile/ingress/scheduler/test fields; out-of-ledger source is not copied.
- The all-disabled exact config contains `plugins.enabled: [dual_coach]`, the manifest/entry point key is `dual_coach`, every behavior flag is false, and isolated install/temp-home tests prove discovery, top-level CLI registration, and preflight with zero operational effects.
- A has private checkout/revision/test/build/wheel evidence, host base compatibility, no fake Hermes PR, and human #74072 disposition only after acceptance. B has independent pinned/tested/built host and plugin artifacts, two source identities, two binary SHA-256s, a compatibility matrix, and a generic-only PR. C has its two-human written exception before any bundled source/PR.
- The dirty original fingerprint is unchanged; no collision reuse/reset/clean/fetch-prune/force-update/delete/merge occurs.
- Reservation/identity/authorization/digest/no-resend and privacy/write-set invariants pass; no Gate-D, provider, customer, activation, delivery, credential, or rollout boundary is crossed.

## Escalation/Risk Gate
Stop and return to named maintainers/architect, not an executor, for invalid-label rejection/no response; no safe A seam; public exception beyond B allow-list; absent C exception; incomplete appendix; Profile mismatch/raw-storage pressure; ingress-order ambiguity; worktree collision/fingerprint drift; missing exact plugin manifest key; discovery/CLI/preflight failure; SHA mismatch; redaction/write/network failure; or PR wrong head. An architect reviews B scheduler/ingress contract; critic re-reviews before B/C PR open. Executor authority ends at offline evidence; no team/ultragoal/deployment lane crosses Gate-D.

## Risks and mitigations
| Risk | Mitigation |
|---|---|
| 6,916-commit/36K-line stale dirty source is mistaken for deployable code | Immutable base, semantic hunk ledger, isolated worktrees, fresh reviewed artifacts; nontechnical warning retained. |
| Host discovery is conflated with behavioral activation | Fix manifest/entry-point key to `dual_coach`; exact allow-list config and temp-home CLI/preflight proof; all behavior flags stay false. |
| Two-repository delivery collapses into one SHA/worktree | Topology matrix gives independent roots, revisions, build commands, binary checksums, compatibility tuple, PR, and rollback. |
| A invents a contentless Hermes PR or requires absent legacy tests | A has no host PR/wrapper requirement; plugin suite/build runs only from `PLUGIN_ROOT`; human alone disposes of #74072 after acceptance. |
| B leaks domain policy into Hermes or conflates claims/reservations | Generic-only allow-list and two-consumer tests; architect gate; separate immutable host/plugin artifacts. |
| I/O/data leakage or resend ambiguity | Recording fakes, zero-write/network checks, redaction assertions, typed fail-closed errors, immutable receipt/audit/no-resend state. |
| Worktree/ref or wrong-head damage | Collision-stop procedure, original fingerprint equality, no force/delete/merge, fresh immutable replacement only. |

## Handoff
Use an executor only after the human topology and ledger gates. Use architect for B/C APIs and scheduler ownership; critic for pre-PR re-review; no deployment or customer-facing role is authorized. This is planning only.
