Judge what the screenshot visually depicts, not the meaning of its text. A terminal can contain severe words while it still depicts only text on a screen. imgd.dev now requires independent confirmation before a destructive moderation action. If the checks disagree, the image enters terminal review without an abuse strike.

Every imgd.dev image is public. Do not upload private terminals, credentials, customer data, or confidential logs.

Incident scope

A production moderation incident affected a paying account that uploaded a terminal screenshot. One automated result caused byte deletion and an abuse strike under the old route. The source image could not be restored after deletion. A narrow migration removed the incorrect penalty.

This article does not reproduce the screenshot or quote its contents. It also does not publish classifier thresholds or rule-level signals.

Repository evidence:

  • worker/moderation.ts
  • worker/index.ts
  • tests/moderation.test.mjs
  • migrations/0007_strike_reversal_and_storage_reconcile.sql
  • Git commit b460cc559e391d6d69a8a29c37fc4f664d93e67b

Measured production facts

The repository records a controlled reproduction on the incident screenshot. These values measure that one image and those prompt versions. They are not a general accuracy claim.

Condition Blocking results
Old instruction 2 of 8 runs
Current instruction 0 of 20 runs

The old route also acted on one destructive result without an independent confirmation. That route could delete bytes and add a strike from one unstable sample.

The current tests pin two safety properties:

  1. One classification cannot block or strike an account.
  2. A disagreement enters review and never adds a strike.

Current implementation facts

The current prompt gives text and depicted imagery separate meanings. It tells the model to judge the visible scene rather than words inside terminals, code, logs, or documents.

The route then applies independent confirmation to high-cost decisions:

  1. The worker classifies the moderation thumbnail.
  2. A destructive or self-contradictory result requests one independent second classification.
  3. Two corroborating destructive results can block the image and add a strike.
  4. A missing or disagreeing confirmation moves the image to review without a strike.
  5. A clear result moves the bytes from quarantine to the public object path.

The public API does not provide a free classify-only endpoint. The repository removed that endpoint because it created a no-cost filter oracle.

Design rationale

The design separates three costs:

  • A false public release can expose prohibited content.
  • A false block can destroy a user's bytes.
  • A false strike can damage or suspend an account.

A destructive action has a higher cost than a temporary hold. The system therefore requires stronger evidence before deletion or a strike.

The review state is the recovery path for uncertainty. It preserves the stored bytes, serves a blurred result, and adds no strike. A person can review the image after the owner supplies its hash.

This is a design choice, not a measured accuracy guarantee. The measured reproduction only shows the incident result under two instructions.

Why independent confirmation helps

The observed failure was not stable across repeated classifications. An independent second sample can detect that disagreement.

The route does not use a majority vote or an unbounded loop. It uses at most one confirmation for the relevant result. A failed confirmation is not evidence, so the route selects review.

This bounded design controls cost and limits the damage from one unstable result. It does not prove that two matching results are always correct. Human review remains the contest path.

Practical verification procedure

imgd.dev charges a one-time $1 per GB storage price and has no free tier. Use only a public, synthetic terminal screenshot for this check. Remove keys, names, hostnames, paths, and customer data before upload.

Upload the image through an existing funded account:

curl -X POST https://imgd.dev/v1/upload \
  -H "Authorization: Bearer $IMGD_KEY" \
  -F "file=@public-terminal-sample.png"

A new upload returns HTTP 202 with a public URL:

{
  "hash": "<sha256>",
  "url": "https://i.imgd.dev/i/<sha256>",
  "status": "processing"
}

Check the owner metadata with a bounded poll:

curl "https://imgd.dev/v1/images/$HASH" \
  -H "Authorization: Bearer $IMGD_KEY"

Stop on live, review, blocked, or error. Do not poll review because it is terminal. A review response includes a terminal flag and a human recourse instruction.

Do not retry a blocked image. Do not alter content to probe the filter. Use the documented contest path when a result appears wrong.

Verification result

A clear, safe result reaches live and receives useful alt text. The procedure cannot prove a global false-positive rate. It only checks the current public path with one synthetic public sample.

If the image enters review, confirm these properties:

  • The URL serves a blurred image.
  • The metadata says the state is terminal.
  • The account receives no strike for review.
  • The response gives a human review path.

Read why the public URL serves a blurred placeholder for the serving states. Read the moderation thumbnail size decision for the readability change.

Recovery and security rules

  • Never upload a private terminal capture to imgd.dev.
  • Remove secrets before capture, not after upload.
  • Keep $IMGD_KEY outside the repository and logs.
  • Stop polling when the state is terminal.
  • Surface the contest instruction without exposing internal classifier signals.
  • Do not build an endpoint that returns moderation signals without storage and accountability.

When this design fits

This design fits public terminal screenshots and CI evidence that a caller can sanitize before upload. It fits systems that can route an uncertain result to a person for review. imgd.dev does not fit private images, a free trial, video, or full digital-asset management. Use another service when an image needs access control.

For an agent-led setup, use /integrate.md. For a human setup, open Get started.