Skip to content

Roll out and cut over the Telegram conversational MVP #128

Description

@alexeygrigorev

Roll out and cut over the Telegram conversational MVP

Status: in progress — automated repair accepted; HUMAN rollout pending
Tags: enhancement, assistant, backend, infra, testing, P1
Parent: #122
Depends on: #126/#127 automated slices on main; Gate A effective apply before
any new app deployment; corrected #131 review/integration/effective Gate B apply
before #128 commit/push
Blocks: Closing #122
Architecture: _docs/CONVERSATIONAL_AGENT_PLUGIN_ARCHITECTURE.md

Current review state

The frozen candidate at base
f08cfc750cebc601db8b71024168741f8ef4aadb is not accepted. Keep it
uncommitted and use it as the rework starting point.

Binding blockers:

The six-control rollout, proposal/execution boundaries, legacy cutover,
readiness shape, redaction, and most of the frozen infrastructure graph passed
specialist review. Rework is deliberately limited to truthful heartbeat
monitoring, bounded ingress-off maintenance I/O, deterministic proofs, and the
resulting #131 graph/IAM correction.

Do not commit, merge, push, deploy, retrieve secrets, call Telegram/providers,
or apply AWS while these gates are open.

Product scope

Ship one private-Telegram conversational rollout for the two implemented
proposal capabilities:

  • todo: propose, revise, explicitly approve, and create one actor-owned todo;
  • Typefully: confirm typed public source, propose/revise, explicitly approve,
    and create one unscheduled/unpublished/unshared saved draft.

#126 continues to own todo/coordinator/outbox semantics. #127 continues to own
Typefully source, approval, account, request, result, and reconciliation
semantics. #128 owns only rollout integration, dark maintenance, readiness,
telemetry, deployment wiring, staged HUMAN verification, and switch rollback.

Exactly six deploy-owned controls

Expose exactly:

Telegram ingress: off | on
execution leasing: off | on
enabled plugins: none | todo | typefully | todo,typefully
Typefully external execution: off | on
voice: off | on
photo: off | on

One immutable strict snapshot accepts only canonical lowercase values and a
sorted unique plugin subset. All code, SAM, and workflow defaults are off.
Reject missing, whitespace-bearing, duplicate, unknown, retired, or
contradictory controls.

Derived behavior remains:

  • runtime availability and result delivery follow Telegram ingress;
  • todo visibility follows the todo plugin;
  • todo dispatch requires execution plus todo;
  • Typefully visibility follows the typefully plugin;
  • Typefully dispatch requires execution, typefully, and Typefully external;
  • voice/photo require ingress plus their individual switch.

Gates run before proposal approval, before lease, and after lease/before
dispatch. Disabling a capability preserves durable state, never interrupts an
already dispatched effect, and never makes an unknown effect retryable.
Typefully preview with external execution off permits revise/cancel/discard but
has no active approval or queue path.

Required rework 1 — truthful heartbeat monitoring

Keep the existing three fixed-key readiness heartbeat rows and the existing
three metric/alarm names. Treat the metric values as scheduled pulse-presence
signals; readiness continues to calculate stored heartbeat age separately.

Use this minimal design:

  1. Add one rate(2 minutes) scheduled event to
    ConversationalExecutionWorkerFunction, enabled only by
    ConversationalExecutionIsEnabled, with a distinct fixed action such as
    conversational-execution-health-pulse.
  2. The worker handler recognizes that action before stream/recovery work. It
    writes only the fixed execution_worker heartbeat and emits exactly
    ExecutionWorkerHeartbeatAgeSeconds = 0; it does not query/lease/recover an
    attempt, call a provider, retrieve a provider secret, or inspect queue
    traffic.
  3. The existing recovery schedule remains rate(2 minutes) and emits exactly
    RecoveryHeartbeatAgeSeconds = 0 only after its scheduled invocation reaches
    the successful pulse point. Idle recovery is healthy.
  4. The existing result-dispatcher schedule remains rate(1 minute) and emits
    exactly ResultDispatcherHeartbeatAgeSeconds = 0 after a successful
    bounded run. An empty outbox is healthy.
  5. Only these three heartbeat alarms change to
    TreatMissingData: breaching. Retain Maximum, threshold > 300, 5-minute
    periods, two evaluation periods, and two datapoints to alarm. Successful
    fixed-zero pulses remain non-breaching; two missing periods can page a
    stopped schedule/function.
  6. All other 14 alarms retain TreatMissingData: notBreaching. Disabled
    execution/ingress conditions still remove their heartbeat alarm and disable
    the related schedules, so an intentionally disabled component cannot page.

Do not add metric math, a monitoring Lambda, a fourth heartbeat alarm, another
metric namespace, or queue-traffic heuristics.

The new SAM schedule event will produce an additional EventBridge rule and
Lambda permission in the transformed template. Freeze their exact logical IDs,
condition/state, target, input, and function ownership. Gate A's accepted
deploy role already covers stack-prefixed EventBridge rule lifecycle/tagging
and worker Lambda Add/RemovePermission; do not add those actions to #131's
observability policy. #131 must add structural coverage proving that reuse.

Required rework 2 — bounded ingress-off maintenance

After webhook authentication but before JSON parsing:

  • measure the raw update in UTF-8 bytes using the same 256 KiB maximum as
    the enabled adapter;
  • reject an oversized update with 413;
  • attempt no Telegram reply, conversation/model/media/plugin/domain/provider
    work, and do not parse the oversized body.

Every ingress-off maintenance or private-chat-redirect sendMessage attempt
must:

  • use one fixed deadline no greater than 5 seconds through an AbortSignal;
  • make at most one attempt and never retry an unknown send outcome;
  • swallow timeout/network failure into the normal safe Telegram webhook
    acknowledgement so Telegram is not invited to repeat a possibly delivered
    reply;
  • log only an allowlisted fixed event/error code, never token, URL, chat/update
    content, body, header, or stack trace.

Add deterministic tests with a non-returning fetch that observes abort within
the configured deadline and an oversized update that receives 413 with zero
reply/downstream calls. Retain positive proofs for authentication, private
maintenance, directed-group redirect, and at most one fixed reply.

Permanent Telegram and safety behavior

The legacy mutating Telegram fallback remains removed/unreachable. In all
states:

  • /todo and /social are static guidance and never write directly;
  • /podcast states that podcast creation is outside this MVP;
  • /start, /help, /status, session controls, private identity, directed
    group redirect, unsupported-document failure, and reviewed media behavior
    remain as accepted;
  • ingress off authenticates and performs only the bounded maintenance behavior
    above;
  • rollback never restores a legacy handler or polling.

Readiness remains admin-only, exact-read/query-bounded, scan-free,
mutation-free, provider/secret-free, and redacted. Telemetry remains
fixed-cardinality and recursively safe.

Frozen application graph after rework

Refreeze from fresh source/build/transforms. The intended observability family
remains:

  • one ConversationalRolloutAlarmTopic, encrypted with alias/aws/sns, ARN
    output only, no stack subscription/topic policy/contact;
  • exactly three new 30-day retained custom log groups wired with
    LoggingConfig;
  • exactly 17 named alarms and one topic action;
  • the three heartbeat alarms use TreatMissingData: breaching; the other 14
    use notBreaching;
  • no dashboard, composite, anomaly, canary, metric/filter/subscription, or
    additional observability resource.

The intended schedule family is:

  • existing execution recovery schedule;
  • new execution worker health-pulse schedule;
  • existing result dispatcher schedule;
  • their exact SAM-generated EventBridge rules and Lambda permissions.

The replacement #128 source and transforms, not the old #131 fixture, are
authoritative.

Acceptance criteria

  • One immutable snapshot exposes exactly six controls, rejects invalid
    combinations, and keeps all defaults off.
  • Plugin/external gates and durable todo/Typefully behavior retain the
    accepted Ship approved conversational todo creation #126/Ship approved Typefully saved-draft creation #127 boundaries.
  • Legacy direct task/social/podcast/fallback mutation is unreachable and
    slash compatibility remains static.
  • Ingress-off authenticates, enforces a 256 KiB pre-parse byte limit, and
    performs only one deadline-bounded maintenance/redirect attempt.
  • Maintenance timeout/abort returns safely without retry, downstream work,
    or sensitive logging.
  • Worker health has an execution-conditioned two-minute no-op pulse
    independent of stream/queue traffic.
  • Recovery and dispatcher use their existing schedules as idle-safe
    successful pulse sources.
  • Successful pulses emit fixed zero; the three heartbeat alarms alone use
    missing-as-breaching; disabled components do not alarm.
  • Deterministic tests prove healthy/idle, one-period gap, stopped/two-period
    missing, disabled, handler-error, and no-work states for all three
    components.
  • Readiness stays fixed-key/bounded/redacted and reports disabled
    components as not_applicable.
  • Telemetry remains fixed-cardinality and drops unsafe values without
    breaking business behavior.
  • Fresh transforms contain one topic, three retained groups, 17 corrected
    alarms, the new worker pulse rule/permission, existing schedules, and no
    prohibited family.
  • Corrected Allow OIDC deployment of Telegram rollout alarms and notifications #131 exactly matches the replacement graph and provides only
    proven tag-on-create plus existing lifecycle permission.
  • The Playwright global setup passes these six explicit canonical dark values
    to its spawned test server, independent of the parent environment:
    CONVERSATIONAL_TELEGRAM_INGRESS_ENABLED=false,
    CONVERSATIONAL_EXECUTION_ENABLED=false,
    CONVERSATIONAL_ENABLED_PLUGINS=none,
    CONVERSATIONAL_TYPEFULLY_EXTERNAL_EXECUTION_ENABLED=false,
    CONVERSATIONAL_TELEGRAM_VOICE_ENABLED=false, and
    CONVERSATIONAL_TELEGRAM_PHOTO_ENABLED=false.
  • Playwright readiness probes GET /api/health and resolves only on HTTP
    200; connection errors, timeouts, and every non-200 response remain
    unready until the bounded startup timeout fails clearly.
  • An automated regression unsets all six controls in the parent process,
    starts the E2E server through the real bootstrap, and proves the child is
    healthy with the six dark defaults rather than inherited ambient values.
  • CI=true npm --prefix backend run test:e2e completes the full suite with
    exit code 0; retries must not mask a server-startup/configuration failure.
  • Production fail-closed validation is unchanged: missing, malformed, or
    contradictory rollout controls still fail outside the test-only E2E
    bootstrap, with no fallback defaults added to production handler/runtime
    parsing.
  • Gate A and corrected Gate B are effectively applied before Roll out and cut over the Telegram conversational MVP #128
    commit/merge/push.
  • [HUMAN] One webhook/no poller, confirmed out-of-band subscription, dark
    maintenance, staged todo/media/Typefully behavior, alarm canaries, and
    reverse rollback pass with sanitized evidence.

Required automated verification

Run and record exact exit codes/counts:

npm --prefix backend test
npm --prefix backend run typecheck
npm --prefix backend run build
npm --prefix backend run test:telegram-transaction
npm --prefix backend run test:execution-transaction
npm --prefix backend run test:todo-transaction
npm --prefix backend run test:typefully-transaction
uv run --with pytest python -m pytest -q tests/infra
make sam-validate
AWS_CONFIG_FILE=.tmp/aws-empty/config \
AWS_SHARED_CREDENTIALS_FILE=.tmp/aws-empty/credentials \
AWS_EC2_METADATA_DISABLED=true \
AWS_DEFAULT_REGION=eu-west-1 \
sam validate --lint --template-file infra/template.full.yaml
make sam-build
git diff --check

Also require:

  • focused handler tests for the worker pulse, recovery pulse, dispatcher pulse,
    256 KiB boundary, oversized rejection, abort deadline, zero retries, and zero
    downstream work;
  • parsed alarm tests proving exactly 3 breaching heartbeat alarms and 14
    notBreaching alarms;
  • fresh isolated dark/execution/ingress/voice/photo/Typefully-external
    transforms and exact schedule/rule/permission inventory;
  • repeated deterministic graph generation and public-safe sentinel scans;
  • Assistant and Architect re-review, then independent Tester and PM acceptance.

The repair requires the focused unset-parent bootstrap/readiness regression and
CI=true npm --prefix backend run test:e2e. Screenshots remain unnecessary
because no frontend surface changes. No real Telegram/provider/AWS action is an
agent test.

Sequencing

  1. SWE fixes the uncommitted Roll out and cut over the Telegram conversational MVP #128 candidate and posts a new fingerprint.
  2. Assistant and Architect re-review the replacement behavior and graph.
  3. Tester and PM review the replacement candidate.
  4. Fresh transforms freeze the exact corrected graph.
  5. Allow OIDC deployment of Telegram rollout alarms and notifications #131 SWE corrects IAM/fixture/tests against that graph; IAM/security Tester
    and PM accept it.
  6. Integrate corrected Allow OIDC deployment of Telegram rollout alarms and notifications #131 into aws-infra/main; a credentialed operator
    applies Gate A/Gate B and verifies effective permissions.
  7. Only then commit accepted Roll out and cut over the Telegram conversational MVP #128 with Refs #128, merge/push main, and let
    normal CI perform the all-off dark deployment.
  8. Add human, run staged HUMAN canaries/reverse rollback, and close Roll out and cut over the Telegram conversational MVP #128 only
    after live gates pass. Close Epic: Deliver a Telegram-first conversational agent MVP #122 last.

Out of scope

Groups/shared context beyond redirect, web conversation/approval, memory,
scheduling/publishing, podcast/SOP mutation, new plugins, generic uploads,
second proposal/execution paths, extra observability families, provider
fallback, secret UI/plaintext credentials, manual app deployment/Lambda patch,
polling, queue purge, destructive state changes, and edits to source repos from
the #128 worktree.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1ImportantassistantAssistant modules and jobsbackendBackend/APIenhancementNew or improved functionalityhumanCode done or issue blocked on human verificationinfraDeployment and infrastructuretestingTests and QA

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions