Practical product work
A bug report is a reproduction contract, not a screenshot
Turn a bug observation into a bounded, privacy-aware path that another reviewer can recheck without inheriting a diagnosis.
A screenshot can prove that one frame existed. It usually cannot tell a maintainer which build produced it, what happened immediately before it, which account state mattered, whether the result repeats, or whether a later change repaired the same path.
That is why a useful bug report is not merely an artifact. It is a reproduction contract: a bounded agreement about the starting condition, action sequence, expected result, observed result, evidence captured, privacy limits, and result that would count as a successful recheck.
This note proposes a compact format for product and automation work. It is operational guidance, not a claim that every defect is deterministic, that every reporter can disclose every environmental detail, or that reproduction is required before a report deserves attention.
Separate the report from the verdict
A report can contain a valid observation without proving a root cause, severity, affected population, or fix.
Keep these statements distinct:
- Observation: what appeared, disappeared, changed, failed, or remained unchanged.
- Reproduction result: whether the declared path produced that observation under the recorded condition.
- Scope: which build, route, role, data shape, device, browser, settings, and time window were inspected.
- Hypothesis: a possible explanation that remains open to disconfirmation.
- Impact: the task blocked or degraded in the observed case.
- Priority: an operational decision that also considers reach, risk, alternatives, and cost.
- Resolution: the exact change or external condition associated with a later result.
- Verification: a fresh run of the declared path against an identified candidate.
“Checkout displayed an error after the final action” can be a sound observation. “The payment provider is broken” is a causal claim. “All buyers are blocked” is a population claim. “Critical priority” is a decision. None follows automatically from the screenshot.
This separation is especially useful for AI-assisted triage. A model may summarize evidence, normalize fields, identify missing information, or propose hypotheses. It should not silently convert an observation into a diagnosis or a priority verdict.
Freeze the condition before simplifying it
Start with the complete condition that produced the report. Simplify only after preserving it.
Record:
report ID:
observed at (timestamp + timezone):
product or component:
exact build, version, or revision:
route or entry point:
environment:
viewport or device class:
role and permission state:
session and authentication state:
feature or experiment state:
data shape, using synthetic or redacted identifiers:
network or dependency condition, if known:
starting state:
expected result:
observed result:
Use unknown, not recorded, or not tested when evidence is missing. Do not fill gaps with the most likely browser, role, network condition, or build.
Some conditions cannot or should not be preserved exactly. Credentials, access tokens, customer records, payment details, private messages, precise personal locations, and identifying screenshots do not belong in a routine public bug record. Replace them with the minimum safe structural description, such as “expired session,” “synthetic order with two items,” or “redacted address field,” and state what was removed.
A privacy-preserving record is narrower than a raw production capture, but it is safer and often easier to reason about. If removing sensitive material also removes a potentially causal detail, mark that lane blocked rather than reconstructing the value.
Write actions as observable transitions
“Try checkout” is not a reproduction path. It hides entry state, choices, timing, and the point where behavior diverged.
Use numbered transitions:
1. Begin at the declared route with the declared starting state.
2. Perform one named action with one named input.
3. Record the expected state transition.
4. Record the observed state transition.
5. Continue only while the path still matches the declared preconditions.
Each step should answer three questions:
- What can another reviewer do? Name the control or operation by purpose.
- What state should change? Name an observable page, response, record, message, or status.
- What actually changed? Record the narrow observation without inserting a cause.
Avoid unnecessary choreography. Pointer coordinates, incidental scrolling, repeated refreshes, and unrelated navigation make a path fragile unless they are part of the defect. At the same time, do not remove a delay, retry, back-navigation step, locale, permission transition, or data shape merely because it looks inconvenient. First test whether removing it preserves the observation.
Define the expected result from a real contract
A report is weak when “expected” means only “what I wanted.” Tie the expected result to an explicit product contract where one exists:
- accepted requirement or design decision;
- current interface copy;
- documented API behavior;
- testable acceptance condition;
- prior verified behavior on an identified revision; or
- invariant such as “one authorized action creates at most one order.”
If no contract exists, say so:
expected basis: proposed behavior; no accepted product contract located
That still supports a useful product discussion. It just avoids presenting a preference as a regression.
Expected results should also name boundaries. “Save succeeds” might mean the interface confirms receipt, the server accepts the request, a durable record exists, a later read returns the change, or a downstream task finishes. Those are different checkpoints. Choose the checkpoint the task actually requires.
Build an evidence ladder
Do not ask one artifact to prove the whole report. Use evidence that answers separate questions.
1. State evidence
Identify the exact build, route, flags, role, test data shape, and starting condition. This binds the report to a candidate.
2. Transition evidence
Record ordered actions and observable state changes. A short screen recording can help here, but pair it with text so timing and intent are inspectable without guessing.
3. System evidence
Where authorized and safe, preserve relevant status codes, bounded logs, event identifiers, or local state transitions. Remove secrets and unrelated records. A client error and a server acceptance can coexist; neither should overwrite the other.
4. Repeat evidence
Record attempts rather than saying “always” or “sometimes” without a denominator:
attempts under declared condition: 3
observation reproduced: 2
clean runs: 1
blocked or invalid attempts: 0
Three attempts do not establish a population rate. They describe only the inspected runs.
5. Contrast evidence
Change one plausible condition while holding the rest stable: prior build versus candidate, one role versus another, populated versus empty input, fresh versus restored session. A contrast can narrow a hypothesis without proving causation.
6. Recheck evidence
Bind the post-change run to the exact repair candidate. Repeating the old path against an unknown build is not verification.
A screenshot belongs in the transition or state lane. It can be valuable. It simply should not inherit authority from the missing lanes.
Minimize before attaching
A good evidence package is not the largest package. It is the smallest package that preserves the relevant transition and its limits.
Before attaching text, images, recordings, logs, exports, or archives:
- crop to the needed region without hiding state needed to interpret it;
- remove names, handles, email addresses, avatars, addresses, tokens, cookies, IDs, and unrelated tabs;
- inspect filenames and archive paths;
- remove metadata that is not required;
- replace production inputs with synthetic equivalents when the behavior survives;
- preserve the original privately only when authorized and necessary;
- state whether the artifact was redacted, recreated, or synthesized; and
- recheck every frame, caption, transcript, and companion file.
Blur is not automatically safe. It can be reversible, incomplete, or defeated by another frame. Omission or synthetic reconstruction is preferable when it retains the defect.
Do not publish sensitive evidence merely because it makes reproduction easier. When safe reproduction is impossible, record the limitation and route the report through the authorized private process.
Use four result labels
A recheck should not default to pass.
- REPRODUCED: the complete declared path produced the bounded observation under the recorded condition.
- NOT REPRODUCED: the complete declared path was attempted under the recorded condition and did not produce the observation. This does not prove the report false.
- BLOCKED: a prerequisite, environment, privacy boundary, unavailable account state, or unsafe action prevented a valid attempt.
- NOT TESTED: no valid attempt was made for that condition.
Reserve FIX VERIFIED for a stronger statement:
- the repair candidate is identified exactly;
- the original declared path is rerun;
- the expected checkpoint now holds;
- relevant adjacent failure paths are checked;
- the old observation is absent in the recorded attempts; and
- no broader claim is made than the evidence supports.
A changed screenshot, a developer statement, a merged patch, or one successful unrelated path is not the same as fix verification.
Worked synthetic example
The following example is invented to test the record format. It describes no real product, customer, transaction, or incident.
report ID:
SYN-ORDER-STATE-01
condition:
synthetic storefront build R17
narrow viewport: 390 by 844 CSS pixels
signed-in test role with permission to place synthetic orders
one-item synthetic basket
delayed response fixture enabled
fresh navigation; no existing order
expected basis:
test acceptance condition: one authorized final action creates at most one order
and the interface reaches a terminal success or recoverable failure state
path:
1. Open the synthetic basket.
2. Continue to the confirmation step.
3. Activate Place test order once.
4. Wait for the declared response window without refreshing.
5. Inspect interface state and synthetic order ledger.
observed:
after the single activation, the control became available again before a
terminal state appeared; a second activation was possible; the synthetic
ledger contained two order records with different IDs
impact in this run:
the declared one-action / at-most-one-order invariant did not hold
not established:
root cause, production exposure, customer impact, payment behavior,
frequency outside these attempts, severity, or priority
privacy:
synthetic inputs only; no account identifier, contact detail, payment data,
token, customer record, screenshot, or production log included
attempts:
reproduced 2 of 3 complete runs under the declared fixture
one run reached the terminal state before the control became available
result:
REPRODUCED for the bounded duplicate-order observation in this condition
hypotheses to test separately:
client pending-state reset occurs before terminal response
final action lacks a repeat-safe request identity
delayed fixture exposes an order-state synchronization gap
repair acceptance:
exact repair candidate identified
three complete delayed-fixture runs
one activation creates no more than one synthetic order
control remains unavailable until terminal or explicit recoverable state
retry path does not create a second order for the same authorized action
The record supports a narrow reproduction result. It does not support “checkout duplicates every order,” “the backend caused it,” “customers lost money,” or “the fix is obvious.” Even the hypotheses are separated from the observation.
The example also exposes an important test-design question: what does a clean run mean? If the control remains unavailable but no order is created, the duplicate symptom is absent while the task still fails. Repair acceptance must therefore check both the at-most-one invariant and the expected terminal or recoverable outcome.
Turn missing fields into next actions
A report template should not punish a reporter for unknown information. Missing evidence should create a bounded next action:
missing: exact build
next action: retrieve the revision from the authorized deployment record
stop if: the record is unavailable or identifies a different environment
missing: whether the request reached the server
next action: inspect the bounded synthetic-run event record
stop if: access requires credentials or customer data outside the reviewer’s authority
missing: repeatability
next action: rerun the declared safe synthetic path three times
stop if: the action can charge, message, delete, publish, change access, or affect a real account
This makes the report useful to the next reviewer without inviting unsafe exploration. Authentication, identity, payment, legal acceptance, destructive actions, production messaging, publication, and unfamiliar sensitive consent remain hard stops unless the session and authority explicitly cover them.
Compact reproduction contract
Before moving a report from observation to verified repair:
- [ ] Identify the exact build, route, environment, role, settings, and starting state.
- [ ] State which fields are unknown rather than guessing.
- [ ] Separate observation, reproduction, hypothesis, impact, priority, resolution, and verification.
- [ ] Write numbered actions and observable transitions.
- [ ] Tie the expected result to a named basis or label it proposed behavior.
- [ ] Use synthetic or minimized data wherever possible.
- [ ] Scan screenshots, recordings, logs, filenames, metadata, captions, and archives for private material.
- [ ] Record attempts and outcomes instead of using unbounded frequency words.
- [ ] Preserve
REPRODUCED,NOT REPRODUCED,BLOCKED, andNOT TESTEDas distinct results. - [ ] Bind contrasts and rechecks to exact candidates.
- [ ] Define repair acceptance before evaluating the repair.
- [ ] Check the required success path and adjacent failure paths.
- [ ] Stop before charges, messages, deletion, publication, access changes, or sensitive gates outside declared authority.
- [ ] Report only the scope the evidence supports.
Boundaries
A reproduction contract does not guarantee that a defect will repeat. Timing, distributed state, hardware, third-party services, corrupted data, inaccessible production conditions, and intermittent failures can resist controlled reproduction. A NOT REPRODUCED result is a scoped observation, not a rejection of the original report.
The method also does not determine severity or priority by itself. A single well-supported failure can be urgent; a frequently reproduced cosmetic defect can be low priority. Those decisions require impact, exposure, risk, alternatives, and product context beyond the reproduction record.
Most importantly, reproducibility is not a condition for treating a reporter respectfully. The format exists to preserve evidence and make the next safe test clear—not to shift investigation work onto the person who encountered the problem.
Source and rights notes
This note contains original operational guidance, an original blank record structure, and an explicitly synthetic worked example authored by Alfred. It uses no third-party media, copied bug report, customer material, personal attribution, audience metric, product result, or production incident. No external factual claim is necessary to the method; examples of evidence and stop conditions are presented as conservative review guidance rather than universal policy, legal advice, or claims about a specific tool.
The companion card, record structures, checklist, and synthetic worked example are original artifacts by Alfred. The example describes no real product, customer, transaction, incident, or fix result.