A community kitchen uses a scheduling app to arrange volunteer pickups. On Monday morning a coordinator discovers that a late Sunday shift is missing from the previous week's export and appears in the next one. Both files generated successfully. The error matters because coordinators use the weekly lists to prepare supplies. Reproduce it with two fictional kitchens, a few synthetic shifts, and a fixed clock. The goal is to show how the date moved, repair the responsible code, and give the next coordinator a way to verify the result.
Write a reproduction that someone else can run
Start with the report type, deployed build, role, selected reporting dates, kitchen timezone and operator timezone. Record when the report was requested and whether it came from the interactive page or a queued export. Ask the business owner how the application assigns shifts to weeks. The viewer's timezone, the kitchen's timezone and the server's timezone can all differ. A coordinator may reasonably expect the kitchen's operational week, but confirm that rule before writing the assertion. Use a redacted row or an invented shift with the same temporal properties in the issue. Avoid copying the entire roster.
In the rehearsal data, give the East Kitchen a Sunday shift at 23:45, a Monday shift exactly at midnight and a midday shift as a control. Add one shift at the West Kitchen to catch accidental scope changes. Give the records stable identifiers, then fix the report generation time at Monday morning. Run the previous week's report for East Kitchen. Save the requested date range, row identifiers, displayed dates and totals. Run the report query independently with the same filters and capture the corresponding response. This first comparison separates a problem in the underlying data path from one that only occurs while creating the file.
Ask someone else to reproduce the exact failure from your notes. They should know which row is misplaced, which nearby row is correct and what build they used. If the report depends on a queued job, capture the job identifier, request parameters and completion status. Wait for a documented terminal state with a deadline. A stale file from a previous run can look like the failure even when the new job produced a correct result. Use distinct run identifiers or clear only the designated test artifacts before repeating the check.
If the bug appears only on the coordinator's machine, request the smallest set of differences likely to matter. Compare the user and kitchen timezone, browser language, build identifier and selected dates with an ordinary workstation. Recreate those settings in isolation and vary one at a time. If you can reproduce the issue only when the server and kitchen use different timezones, record that condition explicitly. A report that says the bug occurs intermittently gives the next investigator less direction than a controlled comparison that says precisely when it appears.
Find the earliest point where the observed result changes
Map the data path from storage to selection, grouping, serialization and rendering. Give each boundary a question that can be answered with evidence. Did the storage query return the Sunday shift? Did grouping already label it as Monday? Does the serialized job payload still carry an offset? Is the date only wrong in the generated file? Capture a compact observation at each relevant boundary. Use the same shift identifier throughout so that a reviewer can trace the same record without needing an entire production log.
Suppose the database returns the correct instant and the API includes the shift in its result, but the grouping step outputs a Monday key. Inspect the export path that supplies the grouping function. In this example, the job converts an instant to the server's local date and time, formats it as a string without an offset, and sends that string downstream. The grouping function interprets it in the kitchen's timezone. Check the hypothesis with a controlled comparison. Keep the same instant and kitchen timezone, then run the actual grouping path once with an offset-aware timestamp and once with the offset removed in the way the job currently removes it. Observe both grouping keys. Repeat with the server timezone set to the kitchen timezone, where the mistaken conversion may happen to produce the same key. Those checks explain both the defect and the condition that hides it.
Keep the investigator's material narrow. Give them the report contract, two sample inputs, two observed outputs and the relevant function and caller. Ask them to predict one new observation that would distinguish their hypothesis from the next plausible one. If grouping always outputs the correct date in the controlled run, inspect the exporter or the cached file instead. Preserve the observation, discard the experimental edit in the isolated worktree, and return to the last confirmed boundary. Updating a hypothesis in response to a counterexample is part of the diagnosis.
For a regression with a known working build and a known failing one, replay the same case on both before trying Git bisection. Pin the dependencies and fixtures as far as the historical versions allow. In a dedicated worktree, classify a build by the actual report row, not by whether the application compiled. A revision that cannot be built or cannot consume the fixture is indeterminate. Keep the classification log and review the change at the boundary. The first failing revision tells you where behavior changed. Still demonstrate how that code produces the observed result on the current branch before committing a repair.
Make a repair whose scope follows the cause
Keep a timestamp with its offset, or an unambiguous instant, through the job payload. Compute the local date at the grouping boundary using the kitchen's approved timezone. Reuse the project's existing conversion code if it already enforces that rule. Add the failing assertion against the old behavior before changing the caller. Then change only the transformation responsible for losing the offset and rerun the same assertion. Review the path that formats dates for display separately. The representation shown to a coordinator may be localized even though internal grouping uses an unambiguous value.
Review the patch against the existing report contract. Check whether the serialized job payload is read by older workers, whether cached keys include a timezone or schema version, and whether downstream tools rely on a particular date field. If mixed versions can process the queue during a rollout, create a synthetic old job and run it against the upgraded worker. Decide with the owner whether to retain a compatible representation for existing jobs or drain a queue before enabling a new format. The repair should keep permission filters and unrelated ordering behavior intact. If compatibility requires an additional change, document the caller and test that boundary explicitly.
Keep code cleanup and unrelated dependency upgrades out of the defect patch unless they are necessary to enforce the rule. Give reviewers a small diff with the reproduction identifier, the earliest failing boundary and the reason the change fixes it. If the test passes only after changing the expected report week, compare the assertion with the business rule. An updated expectation can represent a legitimate contract change, but it needs its own approval and evidence. A patch that suppresses the symptom in one exported column can still leave a wrong row set or total.
Collect four pieces of evidence for the handoff
First preserve the reproduction. Record the build and fixture in which a specific shift appears in the wrong report. Second preserve causal evidence. Show the input before and after the conversion and the grouping keys obtained with and without the offset. Third preserve repair evidence. Run the same scenario before and after the change and show that the shift moves back to the expected week. Fourth collect regression and delivery evidence. Confirm that the Monday boundary remains correct, the midday shift remains unchanged, and the West Kitchen's records stay out of East Kitchen's report. Verify both the interactive and queued report paths when they share the rule.
Add a kitchen in a timezone that observes daylight saving time. Use a date when a local hour repeats or is skipped and decide how the fixture identifies the underlying instant. Run adjacent reporting weeks to ensure the same shift is counted exactly once. Check the complete row set and aggregate counts in both weeks. If a particular export consumer needs the prior date format, replay its parser against the repaired response or file. Record which tests executed and which were unavailable. A passing summary should never absorb a skipped integration check or a missing legacy consumer.
Before rollout, generate a candidate file for a rehearsal kitchen from a fixture that has already been manually labeled. Compare the reported row IDs, local dates and totals. Watch the export queue and review whether older jobs can still complete. Identify cached or previously delivered files for the affected period. Ask the report owner whether those files should be regenerated and how recipients can identify the corrected version. Use the application or operator procedure for regeneration so there is a record of the action. If rollback becomes necessary, first verify that the older worker can handle any jobs created by the repaired build. After rollback, check one ordinary export and confirm that the incident record identifies which version is serving traffic.
Assign each assistant a concrete artifact
A reproduction assistant can turn the incident report into steps, fixtures and a list of missing fields. Give it one example and require an expected result and an observable failure. A log assistant can align a few redacted events by request identifier and point out where their recorded values first diverge. A debugging or repair assistant can investigate the identified caller and propose a bounded patch with evidence. A test assistant can draft assertions for the historical failure and adjacent cases and return the exact commands for replay. Review the output of each on a small case before trusting it with more files or a larger change.
Check that any candidate supports the project's host, language and test runner. Confirm which local folders it reads, whether it writes files or runs commands, and where any logs would be sent. If it only offers suggestions, use the existing local test runner to execute the checks. Ask the assistant to distinguish observations from inferences and executed commands from suggested commands. For a production incident, give it fabricated or sanitized data and keep operational changes with the authorized maintainer. The issue owner remains responsible for the contract and the final decision that the defect is resolved.
For the interactive reproduction and browser regression, Webapp Testing can exercise the running local application with Python and Playwright and produce scripts, screenshots and browser logs. Supply the isolated app address, four synthetic shifts and expected row set. Ask it to verify filters and displayed dates. Keep service grouping and queued export checks in the project test suite. Prepare the app startup instructions, browser dependencies and permission to use the test data before this step.
Keep a short handoff note for the next shift. Include the reproduction command, fixture revision, causal chain, repair commit, rollout identifier and any reports that still need regeneration. Link the regression to the incident so future maintainers can see why it covers a Sunday and a Monday boundary. Record who owns the next action for unresolved reports. Have someone who did not work on the repair use the note to answer which kitchen, week and file version they should verify. Missing context is easier to correct during rehearsal than during the next incident.
Questions that come up during debugging
Can there be a defect if the logs show no exceptions?
Yes. A normal job can produce the wrong business result. Establish the expected membership of the report and compare it with the actual rows and totals. Then add a narrow observation point that reveals the first difference without exposing the underlying roster.
What if only the exported file survives?
Look for the report identifier or generation time and ask the owner to recover the build, filters and job parameters from approved records. If those details are unavailable, treat the file as evidence of the output and test the suspected mechanism using a synthetic fixture. Distinguish the mechanism you can reproduce from the historical conditions you have not confirmed.
When should the investigator abandon a hypothesis?
Design an observation that the hypothesis predicts. If you can reproduce the incident but the predicted change does not occur, document the counterexample and return to the last proven observation. A replacement explanation must account for both the earlier evidence and the new result.
Why run the regression against the old version?
It demonstrates that the check detects the defect. A test that merely asserts the export completed would pass against both builds. The useful regression asserts the expected row, boundary and total. Run it against the repaired version with the same conditions, then include the adjacent cases that could be affected by the change.