I read this as an end-to-end implementation task with strict TDD and worktree-safety gates - I’ll inspect the specification, contracts, repository guidance, current seams, and baseline state first, then either apply the change through the required patch mechanism or return the exact patch if that mechanism is unavailable.


I’ve reached the implementation gate: this session exposes read/edit/write and shell tools, but no direct `apply_patch` tool. Because the task explicitly forbids substituting shell/heredoc/script writes, I will not mutate the dirty repository; I’m completing the seam analysis needed to report the blocker accurately without risking unrelated work.


I read this as an end-to-end implementation task - execution is blocked because the mandated patch mechanism is unavailable, so I preserved the repository unchanged.

```yaml
DoneClaim:
  task: "4. Introduce explicit customer and staff addresses"
  outcome: BLOCKED
  reason: >
    No direct apply_patch tool or apply_patch executable is available.
    The task explicitly prohibits edit/write and shell/heredoc/script-based
    substitutes. Producing an exact verified patch also requires the mandated
    failing-first edit/test cycle, so an unexecuted speculative patch would not
    be an honest DoneClaim.

  baseline:
    repository: /home/cube/projects/richard/hermes-agent
    status_entries: 100
    status_sha256: 6cb07d2bee677cf5be288dff8447a1c077566dc87d1bb7dd09a06a2658b477d1
    manifest_digest: 19ed0e9232e240553b9a96a2e6a33d10f1096be49e5ebafc019287d75984e45c
    inspected:
      - dualcoach-production-readiness.md specification/todo 4
      - immutable candidate manifest JSON
      - Golden Path contract
      - repository AGENTS.md
      - onboarding authority
      - room-bootstrap registration and activation
      - customer registry/coordinator seams
      - adjacent activation and onboarding tests

  failing_first_evidence:
    result: NOT_RUN
    reason: >
      Adding regression tests requires a prohibited repository write.
      No existing test was misrepresented as failing-first evidence.

  changed_files: []

  tests:
    result: NOT_RUN
    reason: No implementation or test changes could legally be created.

  diagnostics:
    ruff: NOT_RUN
    basedpyright: NOT_RUN
    lsp: NOT_RUN
    reason: No changed files exist.

  manual_qa:
    result: NOT_RUN
    reason: The requested parser/types/readiness API does not exist yet.

  adversarial_coverage:
    dirty_worktree: >
      Addressed: read-only inspection; baseline and ending status hashes match.
    stale_state: BLOCKED_UNTESTED
    malformed_input: BLOCKED_UNTESTED
    prompt_injection_untrusted_metadata: BLOCKED_UNTESTED
    cancel_resume: INAPPLICABLE_NO_EXECUTION
    hung_or_long_commands: INAPPLICABLE_NO_EXECUTION
    flaky_tests: INAPPLICABLE_NO_TESTS_ADDED
    misleading_success_output: >
      Addressed: outcome is BLOCKED; no success claim was made.
    repeated_interruptions: INAPPLICABLE_NO_EXECUTION

  cleanup_receipt:
    temporary_files_created: 0
    processes_started: 0
    runtime_state_changes: 0
    customer_changes: 0
    credential_changes: 0
    gateway_changes: 0
    git_operations: "No commit/push/reset/stash/clean/checkout/restore."

  residual_risks:
    - Customer and staff addresses remain overloaded.
    - Shared group/topic customer delivery remains accepted by current seams.
    - Customer staff-group membership is not yet an activation blocker.
    - Legacy shared-topic data lacks the required migration readiness error.
    - Trainer, owner, and operator address parsing is not yet explicitly typed.

  ending_git_status:
    touched_paths: []
    overall_entries: 100
    overall_status_sha256: 6cb07d2bee677cf5be288dff8447a1c077566dc87d1bb7dd09a06a2658b477d1
    baseline_unchanged: true
```

Required capability to resume: expose a direct `apply_patch` tool.


DoneClaim:
  route: "I read this as a patch-only handoff - provide the minimal unexecuted TDD patch and verification commands without mutation."
  task: "4. Introduce explicit customer and staff addresses"
  outcome: PROPOSED_NOT_APPLIED
  mutated: false
  baseline:
    status_entries: 100
    status_sha256: "6cb07d2bee677cf5be288dff8447a1c077566dc87d1bb7dd09a06a2658b477d1"
  failing_first:
    command: ".venv/bin/pytest -q tests/gateway/test_telegram_nutrition_addresses.py"
    expected_failure: "ModuleNotFoundError: No module named 'gateway.platforms.telegram_nutrition_addresses'"
  changed_files:
    - gateway/platforms/telegram_nutrition_addresses.py
    - gateway/platforms/telegram_room_bootstrap_activation.py
    - tests/gateway/test_telegram_nutrition_addresses.py
  touched_file_baseline_risks:
    gateway/platforms/telegram_nutrition_addresses.py: "New file; verify no concurrently-created path before applying."
    gateway/platforms/telegram_room_bootstrap_activation.py: "Untracked baseline candidate containing prior agent work; apply only the narrow import/method hunks."
    tests/gateway/test_telegram_nutrition_addresses.py: "New file; verify no concurrently-created path before applying."
  verification:
    targeted_tests: ".venv/bin/pytest -q tests/gateway/test_telegram_nutrition_addresses.py tests/gateway/test_telegram_room_bootstrap_activation.py tests/gateway/test_telegram_room_bootstrap_registration.py tests/gateway/test_telegram_activation_notice.py tests/gateway/test_telegram_nutrition_onboarding.py"
    ruff: ".venv/bin/ruff check gateway/platforms/telegram_nutrition_addresses.py gateway/platforms/telegram_room_bootstrap_activation.py tests/gateway/test_telegram_nutrition_addresses.py"
    basedpyright: ".venv/bin/basedpyright gateway/platforms/telegram_nutrition_addresses.py gateway/platforms/telegram_room_bootstrap_activation.py tests/gateway/test_telegram_nutrition_addresses.py"
    manual_driver: >-
      .venv/bin/python -c "from gateway.platforms.telegram_nutrition_addresses import *;
      dm=parse_customer_delivery_address({'role':'customer','user_id':'200','chat_id':'200','chat_type':'private','topic_id':'91'});
      staff=[parse_staff_review_address({'role':r,'user_id':u,'chat_id':'-1009','chat_type':'supergroup','topic_id':t},expected_role=StaffRole(r))
      for r,u,t in [('trainer','201','10'),('owner','202','11'),('operator','203','12')]];
      print('happy',dm.topic_id,[x.role.value for x in staff]);
      cases=[
      ('group',lambda:parse_customer_delivery_address({'role':'customer','user_id':'200','chat_id':'-1009','chat_type':'supergroup','topic_id':'9'})),
      ('membership',lambda:validate_activation_address_readiness(customer=dm,reviews=staff,staff_member_user_ids=['200'])),
      ('legacy',lambda:parse_activation_address_readiness(customer={'role':'customer','user_id':'200','chat_id':'-1009','chat_type':'supergroup','topic_id':'9'},reviews=[{'role':r,'user_id':u,'chat_id':'-1009','chat_type':'supergroup','topic_id':t} for r,u,t in [('trainer','201','10'),('owner','202','11'),('operator','203','12')]],staff_member_user_ids=['200'])),
      ('malformed-role',lambda:parse_staff_review_address({'role':'operator','user_id':'201','chat_id':'-1009','chat_type':'supergroup','topic_id':'10'},expected_role=StaffRole.TRAINER))];
      [(print(name,'ERROR: no rejection') if (fn() is not None) else None) for name,fn in []];
      import builtins;
      [builtins.print(name,getattr(e,'code',type(e).__name__),str(e)) for name,fn in cases for e in [next((x for x in [None]),None)] if False];
      exec(\"for name, fn in cases:\\n try: fn(); print(name, 'ERROR: no rejection')\\n except AddressConfigurationError as exc: print(name, exc.code, str(exc))\")"
  expected_manual_output: |
    happy 0 ['trainer', 'owner', 'operator']
    group customer_delivery_not_private Customer delivery must use the customer's private Bot DM; group, supergroup, and topic delivery are not permitted.
    membership customer_in_staff_group Remove the customer from staff group -1009 before activation.
    legacy legacy_shared_topic Configure customer 200 with a private Bot DM and remove that customer from staff group -1009 before activation.
    malformed-role role_confused Expected trainer review address, received operator.
  residual_risks:
    - "Patch is unexecuted because mutation was prohibited."
    - "The activation API is wired as an explicit preflight seam; existing delivery/onboarding routing is intentionally unchanged for task 5."
    - "Callers must supply fresh Telegram staff membership evidence before invoking activation."

Patch_1_of_3:
```diff
diff --git a/gateway/platforms/telegram_nutrition_addresses.py b/gateway/platforms/telegram_nutrition_addresses.py
new file mode 100644
--- /dev/null
+++ b/gateway/platforms/telegram_nutrition_addresses.py
@@ -0,0 +1,235 @@
+"""Strict Telegram customer-delivery and staff-review addresses."""
+
+from __future__ import annotations
+
+import re
+from collections.abc import Iterable, Mapping, Sequence
+from dataclasses import dataclass
+from enum import Enum
+from typing import Final
+
+_ID_RE: Final = re.compile(r"-?[1-9][0-9]*|0")
+_ADDRESS_FIELDS: Final = frozenset(
+    {"role", "user_id", "chat_id", "chat_type", "topic_id"}
+)
+
+
+class AddressConfigurationError(ValueError):
+    """Typed actionable configuration/readiness failure."""
+
+    def __init__(self, code: str, message: str) -> None:
+        self.code = code
+        super().__init__(message)
+
+
+class StaffRole(str, Enum):
+    TRAINER = "trainer"
+    OWNER = "owner"
+    OPERATOR = "operator"
+
+
+@dataclass(frozen=True, slots=True)
+class CustomerPrivateDeliveryAddress:
+    user_id: str
+    chat_id: str
+    topic_id: str = "0"
+
+    @property
+    def key(self) -> tuple[str, str, str]:
+        return (self.user_id, self.chat_id, self.topic_id)
+
+
+@dataclass(frozen=True, slots=True)
+class TrainerReviewAddress:
+    user_id: str
+    chat_id: str
+    topic_id: str
+    role: StaffRole = StaffRole.TRAINER
+
+
+@dataclass(frozen=True, slots=True)
+class OwnerReviewAddress:
+    user_id: str
+    chat_id: str
+    topic_id: str
+    role: StaffRole = StaffRole.OWNER
+
+
+@dataclass(frozen=True, slots=True)
+class OperatorReviewAddress:
+    user_id: str
+    chat_id: str
+    topic_id: str
+    role: StaffRole = StaffRole.OPERATOR
+
+
+StaffReviewAddress = (
+    TrainerReviewAddress | OwnerReviewAddress | OperatorReviewAddress
+)
+
+
+@dataclass(frozen=True, slots=True)
+class ActivationAddressReadiness:
+    customer: CustomerPrivateDeliveryAddress
+    trainer: TrainerReviewAddress
+    owner: OwnerReviewAddress
+    operator: OperatorReviewAddress
+    staff_group_chat_id: str
+
+
+def _record(value: object) -> Mapping[str, object]:
+    if not isinstance(value, Mapping):
+        raise AddressConfigurationError(
+            "malformed_address",
+            "Telegram address must be an object with explicit role and chat type.",
+        )
+    if set(value) != _ADDRESS_FIELDS:
+        raise AddressConfigurationError(
+            "malformed_address",
+            "Telegram address fields must be exactly role, user_id, chat_id, "
+            "chat_type, and topic_id.",
+        )
+    return value
+
+
+def _text_id(value: object, field: str) -> str:
+    if isinstance(value, bool) or not isinstance(value, (str, int)):
+        raise AddressConfigurationError(
+            "malformed_address


type: cancelled

previous_status: running

reason: Revived seam-map request remained live across repeated goal turns without returning; replace with bounded file-specific output-only implementation workers.