Skip to content

feat: report sourceImageTag in the info message (surface worker-code vs WASM version) - #122

Merged
JonathanLennox merged 7 commits into
mainfrom
feat/report-source-image-tag
Aug 7, 2026
Merged

feat: report sourceImageTag in the info message (surface worker-code vs WASM version)#122
JonathanLennox merged 7 commits into
mainfrom
feat/report-source-image-tag

Conversation

@JonathanLennox

Copy link
Copy Markdown
Member

What

Surface the WASM codec's origin (SOURCE_IMAGE_TAG) as sourceImageTag in the info message, alongside the existing gitHash.

Why

The translate Worker has two independently-versioned inputs:

  • worker code — the checked-out ref → reported as gitHash.
  • WASM Opus codec — extracted at deploy time from a Docker image tag (SOURCE_IMAGE_TAG), chosen separately from the code ref.

These can drift, and nothing in info surfaced the codec's origin — so a mismatch was invisible. This bit us for real: DTX worker code was deployed with IMAGE_TAG=latest (a pre-DTX WASM lacking _opus_frame_encoder_set_dtx), the encoder threw on init, and the session silently produced zero translated audio — with only gitHash:"dev" / SOURCE_IMAGE_TAG:"latest" to go on.

With this change the peer (JVB), which already logs the info message, sees both identities side-by-side (gitHash=<worker sha>, sourceImageTag=<codec tag>), so a code/WASM mismatch is obvious at a glance.

Changes

  • worker/translationRuntime.ts buildServerInfo and src/serverInfo.ts: add sourceImageTag from env.SOURCE_IMAGE_TAG (worker) / process.env.SOURCE_IMAGE_TAG (node), conditional (omitted when unset — e.g. the container, where code + codec are one image so it doesn't apply).
  • worker/env.d.ts: type SOURCE_IMAGE_TAG.

No behavior change — SOURCE_IMAGE_TAG is already a deployed var; this only reports it.

Related

Complements a small deploy.sh change (infra) that stamps the worker-code commit into __GIT_HASH__ so gitHash stops being "dev". Each is useful alone; together they make a code/WASM mismatch fully diagnostic. (A follow-up "robust" tier could bake the WASM's own build commit into the image as wasmGitHash.)

Testing

typecheck + typecheck:worker + check:worker-safe clean; full unit suite (620) passes. +10 lines, 3 files.

🤖 Generated with Claude Code

JonathanLennox and others added 2 commits August 6, 2026 16:31
…version)

The translate Worker's `gitHash` is the WORKER CODE's commit, but its WASM Opus
codec is sourced independently at deploy time from a Docker image tag
(SOURCE_IMAGE_TAG). Those two can drift — e.g. worker code from a branch with a
`latest` WASM that predates it — and nothing in the info message surfaced the
codec's origin, so such a mismatch was invisible (a real incident: DTX worker
code shipped against a pre-DTX WASM, silently producing no audio).

Surface `env.SOURCE_IMAGE_TAG` as `sourceImageTag` in the info message
(worker `buildServerInfo` + node `serverInfo`), alongside `gitHash`. The peer
(JVB) already logs the info message, so a code/WASM mismatch is now visible at a
glance. No behavior change; SOURCE_IMAGE_TAG is already a deployed var.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Overview

Small, focused observability improvement: surfaces SOURCE_IMAGE_TAG (the Docker image that provided the WASM Opus codec) as sourceImageTag in the info message, alongside gitHash (the worker code commit). Motivated by a real incident where code and WASM drifted silently. +10 lines across 3 files — clean and minimal.


Code Quality

Pattern consistency ✅ — The conditional guard if (env.SOURCE_IMAGE_TAG) info.sourceImageTag = ... mirrors the existing patterns for sessionId, instanceId, and location in both code paths. Nothing surprising here.

Separation of concerns ✅ — The Node path (serverInfo.ts) reads process.env.SOURCE_IMAGE_TAG directly, which is consistent with how CLOUDFLARE_LOCATION / CLOUDFLARE_COUNTRY_A2 are handled in the same file (not everything needs to go through config.ts for an observability-only field). The Worker path reads from env.SOURCE_IMAGE_TAG in translationRuntime.ts — the correct place for it.

Comment quality ✅ — Comments in all three files explain the why well (independent versioning, drift risk, real incident), not just the what.


Potential Issues

CLAUDE.md not updated ⚠️ — The project convention (stated in CLAUDE.md itself) is: "When making code changes, update CLAUDE.md and BACKENDS.md in the same commit." The info message format is documented in CLAUDE.md (search: gitHash, sourceImageTag), and this PR adds a new field to that format. The description in the Key Components → TranscriberProxy section's sample info JSON should include "sourceImageTag": "..." (conditional on it being set).

SOURCE_IMAGE_TAG not documented in README ⚠️ — The PR description says it's "already a deployed var," but the README's environment variable reference (which CLAUDE.md points to as the canonical list) doesn't appear to have a SOURCE_IMAGE_TAG entry in the diff. Worth adding a line explaining what it is and where it appears in the peer logs.

src/serverInfo.ts is also reached by the container ℹ️ — The comment says "translate-worker deploy only; unset on the container" but the code would surface sourceImageTag for any Node deployment that happens to have SOURCE_IMAGE_TAG set. That's fine behavior (if you set it, you get it), but the comment is slightly narrower than the actual behavior. Not a bug, just a wording note.


Performance / Security

No concerns. This is a one-time read at connection establishment, not a hot path. SOURCE_IMAGE_TAG is a Docker image tag, not a secret.


Test Coverage

No new tests were added. Given the simplicity (a single conditional field append in two places), that's acceptable. If you want belt-and-suspenders coverage, a brief test asserting that the info object from buildServerInfo includes sourceImageTag when the env var is set (and omits it when unset) would be easy to add and would guard against future refactors accidentally dropping it.


Summary

The change is correct, minimal, and solves a real observability gap. The two items worth addressing before merge:

  1. Update CLAUDE.md to include sourceImageTag (conditional) in the info message description — the project's own stated convention.
  2. Add SOURCE_IMAGE_TAG to the README environment variable reference.

Neither is a blocker for the logic itself, but (1) is a stated project requirement.

🤖 Generated with Claude Code

Review follow-ups (#122):
- CLAUDE.md: add `sourceImageTag` to the sample `info` JSON and explain it — the
  translate Worker's WASM codec image tag, reported so a code/WASM mismatch is
  visible against `gitHash` (per the "update CLAUDE.md in the same commit"
  convention for info-message format changes).
- README: add a `SOURCE_IMAGE_TAG` row to the translation env-var reference.
- serverInfo.ts: reword the comment — it surfaces for any deploy that sets
  SOURCE_IMAGE_TAG (in practice the translate Worker), not "translate-worker only".

Docs/comment only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Overview

This is a clean, small, well-motivated change (+14/-1 lines). It surfaces SOURCE_IMAGE_TAG as sourceImageTag in the info message so that a code/WASM version mismatch becomes immediately visible in the peer's logs. The PR description explains the concrete incident that motivated it, which is exactly the right framing.


What's Good

  • Consistent pattern — both paths (src/serverInfo.ts and worker/translationRuntime.ts) use identical conditional logic (if (env/process.env.SOURCE_IMAGE_TAG) info.sourceImageTag = ...), matching the existing style for optional fields (instanceId, sessionId, city, country).
  • Conditional omission is correct — the field is absent when unset (container path, dev), rather than being emitted as null/"". This avoids ambiguity between "not applicable here" and "unset in error".
  • Good documentation — CLAUDE.md and README.md are both updated in the same commit, as required by CLAUDE.md's "Keeping Documentation Current" policy.
  • Comments explain the why — the inline comments in both .ts files make the intent clear (deploy-time vs. code-time versioning, the drift scenario).

Issues / Suggestions

Missing test coverage (minor)

test/unit/serverInfo.test.ts exists and has exactly the right structure (beforeEach/afterEach env-var save/restore) to cover this. There are currently four cases for instanceId/location but nothing for sourceImageTag. Two cases are missing:

it('includes sourceImageTag when SOURCE_IMAGE_TAG is set', () => {
    const saved = process.env.SOURCE_IMAGE_TAG;
    try {
        process.env.SOURCE_IMAGE_TAG = 'v1.2.3';
        const info = buildServerInfo({});
        expect(info.sourceImageTag).toBe('v1.2.3');
    } finally {
        if (saved === undefined) delete process.env.SOURCE_IMAGE_TAG;
        else process.env.SOURCE_IMAGE_TAG = saved;
    }
});

it('omits sourceImageTag when SOURCE_IMAGE_TAG is unset', () => {
    const saved = process.env.SOURCE_IMAGE_TAG;
    delete process.env.SOURCE_IMAGE_TAG;
    try {
        const info = buildServerInfo({});
        expect('sourceImageTag' in info).toBe(false);
    } finally {
        if (saved !== undefined) process.env.SOURCE_IMAGE_TAG = saved;
    }
});

(Alternatively, add 'SOURCE_IMAGE_TAG' to the existing cfEnvKeys cleanup array and place the assertions inside the existing structure.) Not a blocker, but the test file clearly tracks every other optional field — this gap feels like an oversight.

Doc example field ordering (nit)

The CLAUDE.md example places sourceImageTag immediately after gitHash (line 3 in the JSON block), but in src/serverInfo.ts the field is added after sessionId/instanceId in the conditional block — so in an actual session response, it would appear later in the object. JSON objects are unordered per spec and the peer treats this as opaque, so there's no functional impact. Just worth knowing for anyone reading the docs and cross-referencing a real captured message.


Security / Correctness

No concerns. SOURCE_IMAGE_TAG is a server-set deploy-time variable (never user-supplied), and the field is informational only with no runtime effect.

Overall

Approved with the suggestion to add the two test cases. The change is correct, well-scoped, and closes a real operational gap.

Review follow-up (#122): serverInfo.test.ts tracks every other optional
field (sessionId, instanceId, location) but had no case for sourceImageTag.
Add SOURCE_IMAGE_TAG to the env save/restore list and two cases — present
when set, absent when unset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Summary: This PR adds a sourceImageTag field to the info message to surface the Docker image tag from which the Worker's WASM Opus codec was sourced, making code/WASM version mismatches visible alongside gitHash. Motivated by a real production incident.


Overview

The change is minimal (26 additions), touches three runtime files and one test, and is entirely additive — no behavior change unless SOURCE_IMAGE_TAG is set. The motivation is well-documented and the problem it solves is concrete.


Code Quality

src/serverInfo.ts — follows the established conditional-field pattern exactly (same as instanceId, sessionId, location). The Record<string, unknown> return type is intentional (noted in the existing JSDoc), so no type-schema update needed.

worker/translationRuntime.ts — uses env.SOURCE_IMAGE_TAG (correct Worker env access), placed after the config block and before the worker augmentation block. Consistent with how the Node path handles it.

worker/env.d.ts — correctly typed as string | undefined (optional).

Tests — two cases added (set / unset), SOURCE_IMAGE_TAG added to cfEnvKeys for proper cleanup. Both cases are meaningfully different (one asserts the value, the other asserts the key is absent entirely). Good coverage for the Node path.


Minor observations

  1. CLAUDE.md example placement: The info example block shows "sourceImageTag": "abc1234" alongside "runtime": "cloudflare-container". The prose in serverInfo.ts says this field is "unset on the container, where code + codec are one image," so in practice a real container deployment would not emit this field. Showing it unconditionally in the container-runtime example may mildly mislead readers. A comment like // only present when SOURCE_IMAGE_TAG is set or moving it to the Worker-specific section of the docs would clarify. Non-blocking.

  2. No Worker-side test: The worker/translationRuntime.ts path has no test for this new branch. Given the logic is a single if (env.SOURCE_IMAGE_TAG) info.sourceImageTag = ... — identical to the Node path — the risk is negligible, and Worker tests are harder to set up. But worth noting if test coverage is tracked per-path.

  3. Key order: sourceImageTag appears after instanceId in the Node path and after config in the Worker path. JSON key order has no semantic significance, so this is fine — just noting for anyone reading raw wire captures.


Security / Performance

No concerns. SOURCE_IMAGE_TAG is non-sensitive deployment metadata (a Docker image tag like v1.2.3 or latest), appropriate for an observability message. Single env var read per connection — no performance impact.


Documentation

Both CLAUDE.md and README.md are updated in the same PR, consistent with the project's documentation conventions. The README env-var table entry is clear and correctly marks the field as unset-by-default and not used at runtime.


Verdict: LGTM. Clean, well-motivated, minimal change that follows all project conventions. The CLAUDE.md example nuance (point 1) is the only thing worth a second look, but it's non-blocking.

Review follow-up (#122): the sample `info` JSON shows `sourceImageTag`
alongside `"runtime": "cloudflare-container"`, but the container never emits
that field (code + codec are one image there). Note that the block is a
composite of every possible field and that `sourceImageTag`/`worker` appear
only on the translate-Worker path, so the example no longer reads as if the
container emits them.

Docs only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Overview

This PR surfaces SOURCE_IMAGE_TAG as sourceImageTag in the info message for both src/serverInfo.ts (Node) and worker/translationRuntime.ts (Cloudflare Worker). The motivation is solid: the translate Worker has two independently-versioned inputs (worker code via gitHash, WASM codec via Docker image tag), and a silent mismatch already caused a real incident. This is a minimal, focused change.


What's Good

  • Minimal footprint: 26 additions across 5 files.
  • Consistent implementation: both runtimes use the same conditional pattern (if (SOURCE_IMAGE_TAG) info.sourceImageTag = ...) so the field is silently omitted when unset, matching how sessionId and instanceId are handled.
  • Test coverage: the two new tests in serverInfo.test.ts cover both the set and unset cases. SOURCE_IMAGE_TAG is correctly added to cfEnvKeys so the save/restore harness cleans it up between tests.
  • Documentation: README.md gets a table row; CLAUDE.md gets the field in the example block and a note that the example is a composite of conditional fields.

Minor Issues

  1. CLAUDE.md says sourceImageTag is worker-only, but the code adds it to both paths.

CLAUDE.md says: 'sourceImageTag and the worker block are emitted only on the translate-Worker path, not on the container shown by the cloudflare-container runtime here.'

But src/serverInfo.ts (the Node/container path) also gains the if (process.env.SOURCE_IMAGE_TAG) check in this PR. In practice the container will not have SOURCE_IMAGE_TAG set, so the statement is operationally true -- but technically misleading. Worth either rewording to 'in practice only emitted on the translate-Worker path (where SOURCE_IMAGE_TAG is set at deploy); the container omits it because code and codec are co-versioned in the same image', or just dropping the parenthetical about which path emits it.

The same slight imprecision appears in README.md: 'Set by the translate-Worker deploy' implies it cannot be set elsewhere, when the code will surface it anywhere SOURCE_IMAGE_TAG is in the environment.

  1. The CLAUDE.md note for the Worker-hosted /translate info block is not updated.

The existing note reads: 'It intentionally omits the Node message's providersAvailable, config.* ... and instanceId fields.'

sourceImageTag is now a new field added to the Worker info (not omitted), but the note does not mention it. A reader consulting this section will not know it's there. A one-liner like 'It now also includes sourceImageTag when SOURCE_IMAGE_TAG is set' would close the gap.


Verdict

No correctness issues, no behavioural changes at runtime, tests are appropriate. The two documentation nits above are worth a quick fix to keep CLAUDE.md accurate, but they are low-stakes.

Review follow-up (#122): the previous doc pass over-claimed that
sourceImageTag is emitted "only on the translate-Worker path", but the
serverInfo.ts (Node) path gains the same conditional in this PR — it's emitted
by any runtime that has SOURCE_IMAGE_TAG in its environment (in practice only
the translate-Worker deploy sets it; the container omits it because code and
codec are co-versioned in one image). Reword CLAUDE.md and the README row
accordingly, and note in the Worker /translate info-block section that
sourceImageTag is now included when the var is set (it's not among the
omitted fields).

Docs only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Overall: Clean, well-scoped observability improvement. No blocking issues.


Overview

This PR surfaces SOURCE_IMAGE_TAG as sourceImageTag in the WebSocket info message for both the Node/container and Cloudflare Worker runtimes. The field helps diagnose code/WASM version mismatches in the translate Worker deployment, where the WASM Opus codec is versioned independently of the worker code. The motivating incident (DTX code deployed with a pre-DTX WASM codec causing silent failures) is a solid real-world justification.


Code Quality

  • Consistency: Both runtime implementations (src/serverInfo.ts:44 and worker/translationRuntime.ts:83) follow the exact same conditional-omission pattern (if (env.SOURCE_IMAGE_TAG) info.sourceImageTag = ...), consistent with how sessionId, instanceId, and other optional fields are handled throughout the codebase.
  • Truthy check is appropriate: Treating SOURCE_IMAGE_TAG="" the same as unset is correct — an empty string tag carries no useful version identity.
  • No type declaration needed: Both info builders use Record<string, unknown>, so there's no separate type to update; TypeScript is happy and the typecheck passes.
  • Comment quality: The inline comments explaining why the field exists (not just what it is) are clear and give good context for future readers.

Test Coverage

  • New tests in test/unit/serverInfo.test.ts cover both the set and unset cases for the Node path.
  • SOURCE_IMAGE_TAG is correctly added to cfEnvKeys so it gets saved/restored around each test — no leakage between cases.
  • The Worker path (worker/translationRuntime.ts) has no new unit tests, but this is a pre-existing gap (the Worker buildServerInfo had no test coverage before this PR). Given the simplicity of the change there (a single conditional assignment mirroring the Node path), this is acceptable.

Minor Observations

  1. CLAUDE.md composite example (CLAUDE.md:526): The sample info block now shows "sourceImageTag": "abc1234" alongside "runtime": "cloudflare-container". In practice, sourceImageTag is only emitted by the translate Worker (cloudflare-worker), not by the container. The updated prose immediately below does call this out ("The block above is a composite showing every field that can appear; several are conditional and never all co-occur"), so it's not wrong — just worth knowing if the example ever gets split into separate runtime-specific examples in the future.

  2. No forwarding to container via buildContainerEnvVars: This is correct and intentional — the container doesn't need it since code and codec ship together in one image. Calling this out only so the rationale is visible in the review record.


Security / Performance

No concerns — this is a pure observability addition with no behavioral effect and no sensitive data exposure (a Docker image tag is already public information in the deployed environment).


Summary: Ship it. The change is minimal, correct, well-tested on the changed path, and solves a real operational problem. The CLAUDE.md note is a nit, not a blocker.

@JonathanLennox
JonathanLennox merged commit 6e6e6a0 into main Aug 7, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants