{
  "schema": "task26-trainer-free-v1-acceptance-inventory-v2",
  "recorded_at_utc": "2026-08-15T07:26:26Z",
  "purpose": "Machine-checkable acceptance contract for the dedicated trainer-free v1 repair and subsequent Task26 security/privacy re-audit.",
  "current_verdict": "FAIL",
  "checkpoint_observed": false,
  "source_edit_authority": "dedicated repair worker only",
  "adjudicator_actions_allowed": [
    "read candidate and evidence",
    "hash and mode verification",
    "static closure scan",
    "offline unit tests",
    "network-disabled disposable integration tests",
    "write redacted Task26 receipts"
  ],
  "adjudicator_actions_forbidden": [
    "product source edits",
    "live profile mutations",
    "service actions",
    "Telegram or provider actions",
    "delivery actions",
    "git commit, push, or release"
  ],
  "candidate_checkpoint_contract": {
    "required": true,
    "required_fields": [
      "schema",
      "status",
      "recorded_at_utc",
      "execution_head",
      "git_status_porcelain_v1_z_sha256",
      "git_status_entry_count",
      "candidate_manifest_path",
      "candidate_manifest_sha256",
      "candidate_digest",
      "candidate_file_count",
      "v1_runtime_closure_manifest_path",
      "v1_runtime_closure_manifest_sha256",
      "production_wheel_path",
      "production_wheel_sha256",
      "production_wheel_member_count",
      "trainer_free_migration_receipt_path",
      "trainer_free_migration_receipt_sha256",
      "preclean_fixture_manifest_path",
      "preclean_fixture_manifest_sha256",
      "preclean_fixture_receipt_path",
      "preclean_fixture_receipt_sha256",
      "verification_receipt_paths",
      "verification_receipt_sha256",
      "task22_permission_receipt_path",
      "task22_permission_receipt_sha256"
    ],
    "required_values": {
      "status": "READY_FOR_TASK26_SECURITY_READONLY_REAUDIT",
      "hash_algorithm": "sha256",
      "product_profile_service_telegram_provider_delivery_mutations": 0,
      "commits_pushes_releases": 0
    },
    "atomicity": "Every referenced path must be a private, regular, non-symlink file; every declared digest and mode must match in one read-only observation. Any missing, drifting, or mixed-candidate leaf fails the checkpoint."
  },
  "v1_runtime_closure": {
    "definition": "Union of all repository modules statically reachable from enabled production entry points, all repository modules imported during fresh-process startup and the complete customer/owner callback matrix, every configured handler/entry point/script, every source leaf used to build the production wheel, and every project module imported from that wheel during the same matrix.",
    "required_entry_roots": [
      "hermes_cli/main.py",
      "gateway/platforms/telegram.py",
      "gateway/platforms/nutrition_coaching.py",
      "gateway/platforms/nutrition_coaching_proposal.py",
      "gateway/platforms/nutrition_coaching_proposal_validation.py",
      "gateway/platforms/nutrition_coaching_judgment.py",
      "gateway/platforms/nutrition_coaching_judgment_request.py",
      "gateway/platforms/nutrition_coaching_judgment_types.py"
    ],
    "required_absence_controls": [
      {
        "id": "TFV1-LEGACY-RUNTIME-ABSENCE-001",
        "binding_test": "tests/gateway/test_trainer_free_v1_contract.py::test_legacy_runtime_modules_are_absent",
        "target": {
          "module": "gateway.platforms.task23_portable_coach_successor",
          "source_path": "gateway/platforms/task23_portable_coach_successor.py"
        },
        "required_zero_counts": {
          "source_file_count": 0,
          "import_spec_count": 0,
          "production_wheel_member_count": 0,
          "dynamic_import_count": 0,
          "handler_entrypoint_reference_count": 0
        },
        "enforcement": "The candidate-bound absence test and static candidate source, closure, production-wheel, dynamic-import, handler, entry-point, and reference checks must all keep this historical trainer-bearing migration implementation absent and import-inaccessible in production.",
        "failure_policy": "Any nonzero required count is a decisive trainer-free contract failure."
      }
    ],
    "manifest_entry_required_keys": [
      "path",
      "sha256",
      "bytes",
      "mode",
      "reason_in_closure"
    ],
    "manifest_entry_constraints": {
      "file_type": "regular_non_symlink",
      "mode": "0644_or_stricter_non_executable_source; 0755_or_stricter_executable_entrypoint",
      "path_unique": true,
      "sorted_by_path": true
    },
    "historical_exception_policy": {
      "allowed_locations": [
        ".omo/evidence/**",
        ".omo/senpi-task/**",
        "tests/**"
      ],
      "conditions": [
        "Historical evidence may retain trainer terminology without being v1 release evidence.",
        "Negative and historical migration tests may retain trainer literals only when they prove generic rejection or immutable historical authentication.",
        "Trainer-bearing historical migration implementation must not be in the v1 runtime closure, imported by a production root, registered as a handler or entry point, or included as importable production-wheel scaffolding.",
        "The original Task25 archive may remain byte-identical as quarantined historical evidence, but it must not be a runtime input or direct pre-clean fixture input."
      ]
    }
  },
  "global_trainer_free_scan": {
    "scope": "Every text source and metadata value in v1_runtime_closure plus production wheel project members, enabled profile config, active profile state, migrated pre-clean fixture active-v1 state, rendered customer/owner prompts, callback data, and test reports.",
    "encoding": "utf-8",
    "case_sensitive": false,
    "forbidden_regexes": [
      "(?i)(^|[^a-z0-9])trainer([^a-z0-9]|$)",
      "(?i)trainer_[a-z0-9_]*",
      "(?i)[a-z0-9_]*_trainer[a-z0-9_]*",
      "(?i)trainer-review|trainer_review|trainer-session|trainer_session",
      "(?i)claim_trainer|pilot_trainer|trb[0-9]+|pt1:",
      "트레이너",
      "오늘PT기록",
      "PT기록"
    ],
    "explicit_non_forbidden_terms": [
      "training",
      "training_summary"
    ],
    "expected_match_count": 0,
    "failure_policy": "Any match fails. No runtime allowlist, dead-code exception, empty-route exception, compatibility alias, or reject-only trainer literal is accepted; unknown roles and callbacks must fail through generic allowlists."
  },
  "acceptance_gates": [
    {
      "id": "TFV1-CLOSURE-001",
      "category": "closure",
      "check": "Static import closure, dynamic import trace, enabled entry points, and production wheel project members are complete and candidate-bound.",
      "expected": {
        "unhashed_entries": 0,
        "missing_entries": 0,
        "unexpected_dynamic_project_modules": 0,
        "symlinks": 0,
        "digest_mismatches": 0
      }
    },
    {
      "id": "TFV1-FIELD-001",
      "category": "fields",
      "check_type": "ast_symbol_absence",
      "must_be_absent": [
        "ValidatedCoachProposal.trainer_handoff",
        "CoachReview.trainer_handoff",
        "ResolvedCustomer.trainer_bridge",
        "ResolvedCustomer.trainer_dm_bridge",
        "ResolvedCustomer.trainer_private_bridge",
        "CustomerDraft.trainer_user_id",
        "CustomerDraft.trainer_chat_id",
        "CustomerDraft.trainer_topic_id",
        "Role.TRAINER",
        "TopicSlot.TRAINER_REVIEW",
        "RecoverySlot.TOPIC_TRAINER",
        "RecoverySlot.CLAIM_TRAINER",
        "StaffReviewRole.TRAINER",
        "trainer_evidence_digest",
        "trainer_loads",
        "trainer_sessions",
        "trainer_load_version",
        "trainer_ambiguity",
        "trainer_record_state",
        "trainer_destination_digest",
        "_trainer_routes",
        "_trainer_private_selected",
        "_trainer_private_keyboard_chats",
        "_trainer_topic_keyboard_topics"
      ],
      "expected_match_count": 0
    },
    {
      "id": "TFV1-SERIALIZER-001",
      "category": "serializers",
      "check": "All v1 serializers, deserializers, exact-key sets, dataclass projections, JSON ledgers, event projections, provider audit records, and card records contain no trainer-bearing key, role, state, destination, or value.",
      "named_surfaces": [
        "COACH_REVIEW_KEYS",
        "coach_review_to_dict",
        "coach_review_from_dict",
        "ValidatedCoachProposal construction",
        "CoachReview construction",
        "draft ledger read/write",
        "generation ledger read/write",
        "publication outbox role serialization",
        "bootstrap/session serialization",
        "registry serialization",
        "activation projection serialization"
      ],
      "expected": {
        "forbidden_keys": 0,
        "forbidden_values": 0,
        "unknown_extra_key_acceptance": 0,
        "silent_trainer_field_drop_at_runtime": 0
      }
    },
    {
      "id": "TFV1-VALIDATOR-001",
      "category": "validators",
      "check": "Trainer-bearing config, registry entries, model/request context, persisted reviews, callbacks, roles, states, and events fail closed at runtime boundaries; the dedicated offline migration is the only component allowed to consume historical trainer-bearing draft data.",
      "required_tests": [
        "exact response-schema key set remains enforced",
        "old coach-review schema with trainer field is rejected by v1 runtime",
        "registry customer containing trainer route or identifier fails startup/preflight without handler registration",
        "publication outbox accepts only customer and owner/operator roles required by v1",
        "unknown callback role and historical trainer callback namespace are rejected before membership lookup and durable mutation",
        "trainer-bearing authority_context, public_evidence, event, or check-in key is rejected or generically excluded before provider request construction",
        "wrong actor, wrong chat, wrong topic, stale generation, stale revision, duplicate callback, and duplicate send remain no-ops"
      ],
      "expected_failed_open_cases": 0
    },
    {
      "id": "TFV1-PROMPT-001",
      "category": "prompts_and_ui",
      "check_type": "source_constant_and_rendered_surface_scan",
      "surfaces": [
        "customer onboarding and check-in prompts",
        "owner/operator review cards",
        "owner/operator callback acknowledgements",
        "activation and completion notices",
        "operator console output",
        "provider system prompts and model input",
        "reply and inline keyboards",
        "callback namespaces and payloads"
      ],
      "expected_forbidden_matches": 0
    },
    {
      "id": "TFV1-METHOD-001",
      "category": "sender_callback_launcher_methods",
      "check_type": "ast_method_and_reference_absence",
      "must_be_absent": [
        "trainer_private_selection_callback",
        "parse_trainer_private_selection",
        "resolve_trainer",
        "trainer_for",
        "trainer_address_for",
        "trainer_private_customers",
        "trainer_private_menu",
        "resolve_trainer_private_selection",
        "open_trainer_private_launcher",
        "trainer_private_active",
        "trainer_private_bridge_for_callback",
        "handle_trainer_private_text",
        "handle_trainer_private_callback",
        "open_trainer_launcher",
        "bind_trainer_launcher",
        "handle_trainer_text",
        "handle_trainer_callback",
        "_canonical_trainer_sessions",
        "TelegramAdapter._trainer_private_address",
        "TelegramAdapter._trainer_private_reply_markup",
        "TelegramAdapter._ensure_trainer_private_keyboard",
        "TelegramAdapter._trainer_topic_reply_markup",
        "TelegramAdapter._ensure_trainer_topic_keyboard",
        "TelegramAdapter._render_trainer_private_menu",
        "TelegramAdapter._render_trainer_private_info",
        "TelegramAdapter._handle_trainer_private_selection",
        "TelegramAdapter._send_coach_trainer_handoff"
      ],
      "required_dispatch_assertion": "No text handler, callback handler, sender, launcher, menu, keyboard, startup hook, recovery hook, dynamic getattr, or role branch can resolve or invoke a trainer-bearing surface.",
      "expected_definition_count": 0,
      "expected_reference_count": 0
    },
    {
      "id": "TFV1-PROJECTION-001",
      "category": "projections",
      "check": "Current and fixture v1 projections use owner_review and customer/owner roles only.",
      "must_be_absent": [
        "trainer_review",
        "claim_trainer",
        "trainer_session",
        "trainer handoff records",
        "trainer completion role",
        "trainer publication priority",
        "trainer topic or claim card",
        "trainer safety destination",
        "trainer schedule evidence"
      ],
      "required_owner_only_states": [
        "owner_review",
        "draft_created",
        "approved",
        "delivery_pending",
        "delivered",
        "sent_audited",
        "held"
      ],
      "expected_forbidden_projection_count": 0
    },
    {
      "id": "TFV1-ROUTE-001",
      "category": "route_and_config_absence",
      "check": "Enabled configuration, registry schema, runtime route maps, handler registration, membership input, and active state expose only a customer DM route and one owner/operator review route.",
      "required": [
        "customer route is a private DM triple",
        "owner/operator route is exact and distinct from customer route",
        "provider membership receipt proves customer absent from every scoped staff chat",
        "registry/config recursively contain zero trainer-bearing keys or values",
        "runtime owns no third review/trainer space",
        "no trainer marker, invitation, role claim, topic, card, callback namespace, observer, route, or data source is configured",
        "unsafe legacy config fails before service readiness"
      ],
      "expected": {
        "customer_routes": 1,
        "owner_operator_routes": 1,
        "trainer_routes": 0,
        "trainer_memberships": 0,
        "trainer_handlers": 0,
        "trainer_config_fields": 0,
        "customer_memberships_in_staff_chats": 0
      }
    },
    {
      "id": "TFV1-DATA-001",
      "category": "active_profile_data",
      "scope_paths": [
        "config.yaml",
        "customers/registry.json",
        "data/customer-activation-journal.json",
        "data/customer-activation-audit.jsonl",
        "data/owner-actions/**",
        "data/customers/**",
        "data/onboarding/**"
      ],
      "check": "Recursive structural key/value and raw-token scans over existing active-profile paths.",
      "expected_forbidden_key_count": 0,
      "expected_forbidden_value_count": 0,
      "expected_forbidden_raw_token_count": 0,
      "cleanup_expected": {
        "customer_enabled": false,
        "delivery_enabled": false,
        "future_jobs": 0,
        "profile_processes": 0,
        "gateway_state": "inactive/dead"
      }
    },
    {
      "id": "TFV1-ARCHIVE-001",
      "category": "archived_active_v1_draft_migration",
      "original_archive": {
        "id": "2009ac177177839cefddb98f285e27fa",
        "manifest_sha256": "ca4811444e114a06749620b9a44e05c8bd62bc3223ec80b1b5740c832c4a84c1",
        "receipt_sha256": "e81a84a8584400401f83aace36283dee18660144ede11e854758e725796e7fb3",
        "draft_ledger_sha256": "509ba81dc6356134f61d31d33f664ca0531391c62abe7f785aeb51122a2fe4a1",
        "observed_trainer_handoff_fields": 3,
        "observed_nonempty_trainer_handoff_fields": 3,
        "required_policy": "Remain byte-identical, owner-only, explicitly historical/quarantined, and unavailable to runtime or direct fixture loading."
      },
      "successor_requirements": [
        "Create a distinct append-only trainer-free successor archive or fixture projection; never edit the original archive in place.",
        "Bind source archive ID and the three exact source hashes above.",
        "Record a source-record hash to destination-record hash map without customer/model prose.",
        "Preserve draft identity, customer binding, text revision, status, immutable parent/child linkage, generation lineage, approval/send receipts, and event counts.",
        "Replace trainer-scoped review data only with owner/operator safety notes under a new exact schema, or omit it when semantically empty.",
        "Recursively scan migrated active-v1 state for zero forbidden trainer keys and values.",
        "Exclude historical migration receipts from the runtime/fixture active-v1 state closure; retain them only as quarantined provenance.",
        "Sign or hash-chain the deterministic migration receipt and store all successor archive files under owner-only directories."
      ],
      "expected": {
        "original_archive_digest_changes": 0,
        "source_record_count": 3,
        "destination_record_count": 3,
        "unmapped_records": 0,
        "forbidden_fields_in_successor_active_v1_drafts": 0,
        "nonempty_forbidden_fields_in_successor_active_v1_drafts": 0,
        "runtime_reads_of_original_archive": 0
      }
    },
    {
      "id": "TFV1-FIXTURE-001",
      "category": "immutable_preclean_fixture",
      "requirements": [
        "Fixture input is the authenticated trainer-free successor projection, not the mutable live profile and not the original trainer-bearing archive.",
        "Fixture manifest records every path, type, mode, size, SHA-256, symlink target, source archive hashes, migration receipt hash, and candidate digest in deterministic order.",
        "Fixture root and directories are 0700; data files are 0600; fixture is regular-file/symlink-safe and read-only during testing.",
        "The test copies the immutable fixture to a writable disposable root and bind-mounts only that copy over the expected profile path inside bubblewrap.",
        "Test and harness do not read the live profile as fixture input; live-profile before/after tree hashes remain equal.",
        "Network is disabled with bubblewrap --unshare-net; Telegram and provider mocks remain at their HTTP transport boundaries.",
        "No fixed sleep or timing-luck polling is used.",
        "Reports contain counts, hashes, statuses, and transport method names only; no raw customer/model text, secrets, route identifiers, or callback data."
      ],
      "precondition_state": {
        "synthetic_customer_count": 1,
        "enabled_synthetic_customer_count": 1,
        "current_regenerable_draft_count": 1,
        "current_generation_state": "draft_created",
        "current_owner_review_card_count": 1,
        "generation_provider_receipt_count": 2,
        "delivery_count": 0,
        "trainer_route_count": 0,
        "trainer_field_count": 0
      },
      "real_handler_expected_counts": {
        "callback_ack_count": 12,
        "card_edit_count": 12,
        "customer_send_count": 1,
        "staff_send_count": 2,
        "draft_created_event_delta": 2,
        "draft_edited_event_delta": 1,
        "draft_approved_event_delta": 1,
        "draft_sent_event_delta": 1,
        "new_draft_count": 2,
        "new_review_card_count": 2,
        "terminal_child_card_count": 1,
        "terminal_delivery_status": "sent_audited",
        "stale_repeat_wrong_role_extra_durable_mutations": 0,
        "stale_repeat_wrong_role_extra_customer_sends": 0,
        "post_restart_duplicate_sends": 0
      },
      "expected": {
        "fixture_source_tree_changes": 0,
        "live_profile_tree_changes": 0,
        "external_network_calls": 0,
        "integration_failures": 0
      }
    },
    {
      "id": "TFV1-TASK22-PERM-001",
      "category": "task22_evidence_permissions",
      "canonical_files": [
        {
          "path": ".omo/evidence/dualcoach-task-22-evidence-index.json",
          "required_mode": "0600",
          "required_sha256": "cc4ac1264d947226f0e2ebfdd2f3845781d48ab298a71ae96c09517eecb26309"
        },
        {
          "path": ".omo/evidence/dualcoach-task-22.md",
          "required_mode": "0600",
          "required_sha256": "4e09d1af33ddec6284f5ac8ddb833cdff1b32e0c59d73f92360795917550c7ac"
        },
        {
          "path": ".omo/evidence/dualcoach-task-22-pre-supplemental-evidence.json",
          "required_mode": "0600",
          "required_sha256": "9c27354011d4050e4fc5bbb18efbdd8f56360d74e8b8dc18098fa6cc9e6b55b3"
        }
      ],
      "parent_directory": {
        "path": ".omo/evidence",
        "required_mode": "0700"
      },
      "referenced_child_receipts": [
        {
          "sha256": "030c942906cac551d8e9574e5d0dde85f3ed3733bf127bb7be777b954288aae8",
          "required_access": "owner-only through ancestor directories; immutable 0400 or 0444 file mode accepted"
        },
        {
          "sha256": "72c6a604fa4a57acaff9940a720bc452bdb606aa57fe391e70a5b2c8ccd6bf4f",
          "required_access": "owner-only through ancestor directories; immutable 0400 or 0444 file mode accepted"
        },
        {
          "sha256": "3194181dc1d672d718d16deeaba9ba80c7df3fa3802a7d36aec6c52cb59a11db",
          "required_access": "owner-only through ancestor directories; immutable 0400 or 0444 file mode accepted"
        }
      ],
      "requirements": [
        "Canonical Task22 files are regular non-symlinks owned by the adjudication user.",
        "Permission repair is chmod-only: canonical bytes and SHA-256 values above remain unchanged.",
        "No canonical Task22 data file has group or other permission bits.",
        "Every indexed path exists and every indexed digest still matches.",
        "Write a 0600 redacted permission receipt containing before/after modes and unchanged hashes."
      ],
      "expected": {
        "canonical_mode_mismatches": 0,
        "canonical_hash_changes": 0,
        "index_reference_mismatches": 0,
        "privacy_exposure_paths": 0
      }
    },
    {
      "id": "TFV1-REGRESSION-001",
      "category": "prior_security_privacy_controls",
      "must_still_pass": [
        "customer DM isolation and customer absence from staff chat",
        "Owner-only approval and send authority",
        "wrong actor, role, chat, and topic fail closed",
        "stale card, stale generation, stale check-in revision, stale draft revision, and wrong render identity fail closed",
        "duplicate callback and duplicate send are durable no-ops",
        "callback acknowledgement occurs before background work without weakening authority checks",
        "generation and delivery CAS remain lock-protected and restart-safe",
        "request fingerprint and exact response schema remain candidate-bound",
        "untrusted customer notes remain fenced from instructions",
        "validation diagnostics and reports retain hashes/codes only",
        "exactly one synthetic customer delivery and zero real-customer delivery",
        "cleanup remains disabled, stopped, job-free, process-free, and orphan-free",
        "original and successor archive integrity and owner-only permissions pass"
      ],
      "expected_failures": 0
    },
    {
      "id": "TFV1-CANDIDATE-001",
      "category": "immutable_candidate",
      "check": "One manifest binds current source, scripts, tests, fixture, migration, closure, wheel, verification receipts, HEAD, and NUL-framed status snapshot.",
      "expected": {
        "candidate_digests_in_release_graph": 1,
        "unbound_files": 0,
        "digest_mismatches": 0,
        "mode_mismatches": 0,
        "mixed_historical_candidate_pins": 0,
        "verification_failures": 0
      }
    }
  ],
  "required_reaudit_execution": {
    "order": [
      "authenticate checkpoint and candidate graph",
      "recompute closure and production wheel membership",
      "run global trainer-free scan",
      "validate profile/config/routes and migrated archive structurally without exposing values",
      "verify Task22 permissions and unchanged hashes",
      "run focused trainer-free, authority, callback, CAS, request/schema, and redaction tests",
      "run the network-disabled real-handler integration exactly once from the immutable fixture",
      "verify build/wheel and all candidate-bound receipts",
      "issue final redacted Task26 verdict receipt"
    ],
    "pass_rule": "PASS only if every acceptance gate reports its exact expected values and there are no unresolved security/privacy findings or unbound evidence leaves.",
    "fail_rule": "Any trainer-bearing v1 closure match, historical runtime reachability, fixture/live dependency, authority/privacy regression, mode/hash mismatch, test failure, or candidate drift is a decisive FAIL."
  }
}
