Skip to content

    SAMPLE: a fictional business. Not a client of Adwaizer.

    Software fix: written scope, failing test, fix summary and handover for Ferngate Cycle Hire (sample)

    Prepared by: Adwaizer AI Consulting Inc. · Engagement: Software fix or small feature, Starter tier (one fix in one repository, 5 working days) · Report version: sample, October 2026

    What this page is. This is everything a client receives on a software fix order: the written scope on day 1, the failing test on day 2, the fix summary on days 3-4 and the handover note, acceptance checklist and Upwork milestone text on day 5. Ferngate Cycle Hire, its repository ferngate/booking-api and every file, test, commit, pull request and number below are invented to show the format and depth; none of them exist. In a real order every row points to the client's own repository, pull request and test run.

    How to read the evidence. "Evidence" is what the client can open and check: a file and line in their repository, a test name, a command and its output. Nothing here was run against a real application.


    1. Written scope (day 1, agreed in writing before any build)

    Ferngate Cycle Hire is a fictional bike rental shop. Its booking API is a Python 3.12 FastAPI app with a PostgreSQL database and a pytest suite. The owner reported one bug through Upwork messages, with two screenshots of the booking page.

    Run before any change. We cloned the repository at main @ 4be1c07 (fictional), followed the README (pip install -r requirements-dev.txt, pytest) and recorded today's result: 96 passed, 0 failed, 2 skipped (the two skips need a live payment sandbox and are skipped in the client's CI too).

    ItemAgreed
    The one bugA bike that is returned at a given time cannot be booked by the next customer from that same time. Example from the client: bike #14 booked 10:00-13:00, then a request for 13:00-16:00 on the same day is refused with "This bike is not available for the times you chose."
    Expected behaviour (client's words)"If a bike comes back at 1, someone else should be able to take it at 1. Back-to-back bookings are how we fill the weekend."
    What is seenHTTP 409 from POST /bookings with {"detail": "bike_unavailable"} for any booking that starts exactly when another ends, or ends exactly when another starts
    Files likely touchedapp/bookings/availability.py (the overlap check); a new test in tests/bookings/test_availability.py
    Out of scopeThe buffer time between bookings for cleaning (the client asked about it; it is a new feature, quoted separately if wanted); the booking page front end; the payment flow; any database migration; the two skipped payment tests
    Acceptance checksThe four checks in section 4.2

    Risk and issue log (day 1).

    #Risk or issueOwnerStatus
    R1Bookings are stored in local time without a time zone; a fix that compares times differently could shift bookings around the daylight-saving changeAdwaizerClosed on day 3: the fix keeps the same comparison type and the existing DST tests still pass
    R2The repository's .env.example holds a placeholder payment key only; no real key was found in the repository or its historyAdwaizerClosed: nothing to rotate
    I1The client's CI runs on pushes to main only, so a pull request does not show a CI runClientOpen: the test run is shown in the pull request description instead (section 3.3)

    The scope above was sent through Upwork messages on day 1 and the client replied "Yes, go ahead" the same day. No build started before that reply.


    2. The failing test (day 2)

    The bug reproduces on the client's current code in their own framework (pytest). The test books bike #14 for 10:00-13:00 and then asks for the same bike from 13:00 to 16:00. It also checks the case the client did not mention but the same line causes: a booking that ends exactly when an existing one starts.

    # tests/bookings/test_availability.py
    from datetime import datetime
    
    import pytest
    
    from app.bookings.availability import is_available
    from tests.factories import make_booking
    
    
    @pytest.mark.parametrize(
        "start, end",
        [
            ("2026-10-24T13:00", "2026-10-24T16:00"),  # starts when the earlier booking ends
            ("2026-10-24T07:00", "2026-10-24T10:00"),  # ends when the earlier booking starts
        ],
    )
    def test_back_to_back_booking_is_available(db, start, end):
        make_booking(db, bike_id=14, start="2026-10-24T10:00", end="2026-10-24T13:00")
    
        assert is_available(
            db,
            bike_id=14,
            start=datetime.fromisoformat(start),
            end=datetime.fromisoformat(end),
        )
    
    
    def test_overlapping_booking_is_still_refused(db):
        make_booking(db, bike_id=14, start="2026-10-24T10:00", end="2026-10-24T13:00")
    
        assert not is_available(
            db,
            bike_id=14,
            start=datetime.fromisoformat("2026-10-24T12:59"),
            end=datetime.fromisoformat("2026-10-24T16:00"),
        )
    

    Result on the client's current code (pytest tests/bookings/test_availability.py):

    FAILED tests/bookings/test_availability.py::test_back_to_back_booking_is_available[2026-10-24T13:00-2026-10-24T16:00] - assert False
    FAILED tests/bookings/test_availability.py::test_back_to_back_booking_is_available[2026-10-24T07:00-2026-10-24T10:00] - assert False
    PASSED tests/bookings/test_availability.py::test_overlapping_booking_is_still_refused
    2 failed, 1 passed
    

    The two back-to-back cases fail, which is the client's bug. The overlap case passes today and must keep passing after the fix, so a real double booking is still refused.

    Root cause. app/bookings/availability.py, line 31 (fictional) treats two bookings as overlapping when existing.start <= requested.end and requested.start <= existing.end. With <=, a booking ending at 13:00 and one starting at 13:00 count as overlapping. Booking times are half-open (a bike returned at 13:00 is free at 13:00), so the comparison needs <.

    Gabriel read the failing test on day 2 and confirmed with the client that it shows their bug.


    3. Fix summary (days 3-4)

    3.1 The change in words

    One comparison changed in one function: in is_available, two bookings now overlap only when existing.start < requested.end and requested.start < existing.end. Nothing else in the booking logic changed. The SQL query that loads candidate bookings used the same <= filter, so it was changed to < in the same way; without that the query would still return the back-to-back booking and the function would refuse it.

    FileChange
    app/bookings/availability.pyThe overlap test and the candidate query use < instead of <= (2 lines), plus a one-line comment that booking times are half-open
    tests/bookings/test_availability.py (new)The three tests from section 2

    Pull request: ferngate/booking-api#41 (fictional), from the branch fix/back-to-back-bookings. Diff: +46 / -2 lines in 2 files. No dependency, migration, setting or environment variable changed.

    3.2 Considered and left alone

    • A cleaning buffer between bookings. The client mentioned wanting 15 minutes between hires. That changes the rule rather than fixing it, so it is out of scope and listed in the handover note as a possible next order.
    • Time zones. Bookings are stored without a time zone (R1). The fix does not change that; changing it would touch every booking row.

    3.3 Checks run on the change

    CheckResult
    New tests on the old code2 failed, 1 passed (section 2)
    New tests with the change3 passed
    Full suite (pytest)99 passed, 0 failed, 2 skipped (96 existing + 3 new; the same 2 payment-sandbox skips as on day 1)
    Lint and typecheck of the changed files (ruff check, mypy app/bookings/availability.py)0 errors
    Separate reviewer session against the written scopeApproved; only the two scoped files changed; asked for the half-open comment, which was added
    Secret scan of the commits (gitleaks)No leaks found
    Gabriel's read of the reviewed pull requestApproved for handover

    4. Handover note and acceptance checklist (day 5)

    4.1 Handover note

    What changed and why. A bike returned at a given time can now be booked from that same time. The availability check treated a booking ending at 13:00 and one starting at 13:00 as a clash; it now treats booking times as "from the start, up to but not including the end", which is how the shop already works at the counter. A real overlap (even one minute) is still refused.

    How to run the new test.

    pip install -r requirements-dev.txt
    pytest tests/bookings/test_availability.py
    

    Expect 3 passed. To see the bug on your old code, check out main before the pull request, keep the new test file, and run the same command: the two back-to-back cases fail.

    What to check in the app after you merge. On your staging site, book any bike for 10:00-13:00, then book the same bike for 13:00-16:00. The second booking is accepted. Then try 12:30-16:00: it is refused.

    Found and left alone.

    ItemWhy it mattersSuggested next step
    Cleaning buffer between bookingsYou asked about it; it is a new rule, not this fixA separate small-feature order if you want it
    Booking times stored without a time zoneA risk around the daylight-saving change if you ever open a second location in another zoneNothing needed today; worth a look before any multi-location work
    CI runs on main onlyA pull request shows no test run until it is mergedAdd pull_request to the trigger in your CI file (a one-line change you can make)

    4.2 Acceptance checklist (for the client)

    1. The new test fails on your old code and passes with the change (pytest tests/bookings/test_availability.py).
    2. Your existing test suite still passes (pytest: 99 passed, 2 skipped, as shown in the pull request).
    3. On staging, a back-to-back booking for the same bike is accepted and an overlapping one is refused, as described in the handover note.
    4. No file changed outside app/bookings/availability.py, except the new test file.

    A failed check is fixed within 5 working days at no charge. You merge the pull request and deploy it; we never merge to your main branch or deploy.


    5. Upwork milestone submission text

    Hi, the fix for back-to-back bookings is ready for your review.

    • Pull request: ferngate/booking-api#41 (2 files: the availability check and a new test file).
    • What changed: a bike returned at a given time can now be booked from that same time; overlapping bookings are still refused.
    • Proof: the new test fails on your current code and passes with the fix. Your full suite passes (99 passed, 2 skipped, the same 2 skips as before).
    • The handover note in the pull request explains how to run the test, what to check on staging, and three things we noticed and left alone (the cleaning buffer you mentioned is one of them).

    Please go through the 4-item acceptance checklist in the pull request. If anything does not check out, tell me here and we fix it within 5 working days at no charge. Once you are happy, please approve this milestone and merge the pull request yourself; we do not merge or deploy.

    Thank you.