===== bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/place-scripts] 2026-07-12T18:13:21.888251508-05:00 2026/07/12 23:13:21 Decoded script /tekton/scripts/script-0-jkx7r [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:27.907495625-05:00 ==> uploading /workspace/shared/artifacts/ -> s3://tekton-logs/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/ (endpoint http://10.10.0.10:9000) [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:28.634943579-05:00 upload: ../workspace/shared/artifacts/junit-sendable.xml to s3://tekton-logs/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/junit-sendable.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:28.636535000-05:00 upload: ../workspace/shared/artifacts/junit-traits.xml to s3://tekton-logs/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/junit-traits.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:28.641823210-05:00 upload: ../workspace/shared/artifacts/coverage-traits.xml to s3://tekton-logs/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/coverage-traits.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:28.641838900-05:00 upload: ../workspace/shared/artifacts/coverage-sendable.xml to s3://tekton-logs/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/coverage-sendable.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/step-upload-artifacts] 2026-07-12T18:13:28.752487582-05:00 ==> viewer URL: https://ci-logs.storeminder.ai/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/artifacts/ [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-artifacts-pod/prepare] 2026-07-12T18:13:20.655204258-05:00 2026/07/12 23:13:20 Entrypoint initialization ===== bootstrap-pr-report-check-pr244-jvhqk-archive-logs-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-logs-pod/place-scripts] 2026-07-12T18:13:21.897494024-05:00 2026/07/12 23:13:21 Decoded script /tekton/scripts/script-0-btzhh [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-logs-pod/place-scripts] 2026-07-12T18:13:21.920969649-05:00 2026/07/12 23:13:21 Decoded script /tekton/scripts/script-1-5dxdl [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-logs-pod/step-collect-logs] 2026-07-12T18:13:31.268583400-05:00 ==> collecting pod logs for PipelineRun=bootstrap-pr-report-check-pr244-jvhqk [pod/bootstrap-pr-report-check-pr244-jvhqk-archive-logs-pod/prepare] 2026-07-12T18:13:20.845941808-05:00 2026/07/12 23:13:20 Entrypoint initialization ===== bootstrap-pr-report-check-pr244-jvhqk-clone-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-clone-pod/prepare] 2026-07-12T18:09:42.718854378-05:00 2026/07/12 23:09:42 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-clone-pod/place-scripts] 2026-07-12T18:09:43.341097893-05:00 2026/07/12 23:09:43 Decoded script /tekton/scripts/script-0-4w2l2 [pod/bootstrap-pr-report-check-pr244-jvhqk-clone-pod/step-clone] 2026-07-12T18:09:50.458287866-05:00 From https://github.com/storeminder-ai/bootstrap [pod/bootstrap-pr-report-check-pr244-jvhqk-clone-pod/step-clone] 2026-07-12T18:09:50.458319056-05:00 * branch 0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 -> FETCH_HEAD [pod/bootstrap-pr-report-check-pr244-jvhqk-clone-pod/step-clone] 2026-07-12T18:09:50.477704375-05:00 Cloned 0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 ===== bootstrap-pr-report-check-pr244-jvhqk-live-build-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/prepare] 2026-07-12T18:10:13.860023825-05:00 2026/07/12 23:10:13 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/place-scripts] 2026-07-12T18:10:15.287602138-05:00 2026/07/12 23:10:15 Decoded script /tekton/scripts/script-0-mjtsr [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/place-scripts] 2026-07-12T18:10:15.311274892-05:00 2026/07/12 23:10:15 Decoded script /tekton/scripts/script-2-jxcrp [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.047436101-05:00 Wrote Dockerfile.reportcheck: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048280306-05:00 # Throwaway PR image for the D2 live report build. Layers the PR checkout [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048290346-05:00 # (src + tests + fixtures + notebooks) over the prod runtime so the D1 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048294676-05:00 # trait suite can run with real deps + real secrets (mounted by the Job). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048299616-05:00 FROM registry.storeminder.ai/images/storeminder:latest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048303466-05:00 COPY . /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048308196-05:00 WORKDIR /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048311976-05:00 # Overlay the PR package over the baked one (deps already resolved in the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048315596-05:00 # base), then add the test runner. Prefer the [test] extra (D1/#90 adds [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048319376-05:00 # papermill/nbclient/scrapbook there); fall back to bare pytest pre-D1. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-prepare-dockerfile] 2026-07-12T18:10:21.048323516-05:00 RUN pip install --no-cache-dir --no-deps -e /prsrc && (pip install --no-cache-dir -e ".[test]" || pip install --no-cache-dir pytest) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.278577205-05:00 INFO[0000] Retrieving image manifest registry.storeminder.ai/images/storeminder:latest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.278612895-05:00 INFO[0000] Retrieving image registry.storeminder.ai/images/storeminder:latest from registry registry.storeminder.ai [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.324321532-05:00 INFO[0000] Retrieving image manifest registry.storeminder.ai/images/storeminder:latest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.324348562-05:00 INFO[0000] Returning cached image manifest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.336870210-05:00 INFO[0000] Built cross stage deps: map[] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.336885360-05:00 INFO[0000] Retrieving image manifest registry.storeminder.ai/images/storeminder:latest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.336891320-05:00 INFO[0000] Returning cached image manifest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.336896200-05:00 INFO[0000] Retrieving image manifest registry.storeminder.ai/images/storeminder:latest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.336901090-05:00 INFO[0000] Returning cached image manifest [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.337040519-05:00 INFO[0000] Executing 0 build triggers [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.337292708-05:00 INFO[0000] Building stage 'registry.storeminder.ai/images/storeminder:latest' [idx: '0', base-idx: '-1'] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.349304409-05:00 INFO[0000] Checking for cached layer registry.storeminder.ai/images/cache:f5401450489b0f7be50124b33bfa7b0f416eeb2466500d9d7110ce663f2ada42... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.377817506-05:00 INFO[0000] No cached layer found for cmd RUN pip install --no-cache-dir --no-deps -e /prsrc && (pip install --no-cache-dir -e ".[test]" || pip install --no-cache-dir pytest) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:21.377833386-05:00 INFO[0000] Unpacking rootfs as cmd COPY . /prsrc requires it. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.146367518-05:00 INFO[0008] COPY . /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.179899246-05:00 INFO[0008] Taking snapshot of files... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235218068-05:00 INFO[0009] WORKDIR /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235246638-05:00 INFO[0009] Cmd: workdir [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235252368-05:00 INFO[0009] Changed working directory to /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235340678-05:00 INFO[0009] No files changed in this command, skipping snapshotting. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235363007-05:00 INFO[0009] RUN pip install --no-cache-dir --no-deps -e /prsrc && (pip install --no-cache-dir -e ".[test]" || pip install --no-cache-dir pytest) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235368707-05:00 INFO[0009] Initializing snapshotter ... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:30.235373117-05:00 INFO[0009] Taking snapshot of full filesystem... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:37.534354480-05:00 INFO[0016] Cmd: /bin/sh [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:37.534461529-05:00 INFO[0016] Args: [-c pip install --no-cache-dir --no-deps -e /prsrc && (pip install --no-cache-dir -e ".[test]" || pip install --no-cache-dir pytest)] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:37.534475599-05:00 INFO[0016] Running: [/bin/sh -c pip install --no-cache-dir --no-deps -e /prsrc && (pip install --no-cache-dir -e ".[test]" || pip install --no-cache-dir pytest)] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:37.857542065-05:00 Obtaining file:///prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:37.859706722-05:00 Installing build dependencies: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:39.890408916-05:00 Installing build dependencies: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:39.891236202-05:00 Checking if build backend supports build_editable: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:39.998415766-05:00 Checking if build backend supports build_editable: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:39.999323451-05:00 Getting requirements to build editable: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.153229988-05:00 Getting requirements to build editable: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.154327411-05:00 Preparing editable metadata (pyproject.toml): started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.314798170-05:00 Preparing editable metadata (pyproject.toml): finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.357922533-05:00 Building wheels for collected packages: storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.358698388-05:00 Building editable for storeminder (pyproject.toml): started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.532483091-05:00 Building editable for storeminder (pyproject.toml): finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.533154747-05:00 Created wheel for storeminder: filename=storeminder-0.1.0-0.editable-py3-none-any.whl size=1909 sha256=ef1666d4ec68576d241f0097bf6bcb8bb304664bce6d731f9bf0eadd9d94a752 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.533296536-05:00 Stored in directory: /tmp/pip-ephem-wheel-cache-xg3hfxkx/wheels/12/13/ba/810e66e2be1a8a55fa7c56f5f12815f8d07be3aad27f734654 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.535735812-05:00 Successfully built storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.535877861-05:00 Installing collected packages: storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.536025910-05:00 Attempting uninstall: storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.575782892-05:00 Found existing installation: storeminder 0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.580567565-05:00 Uninstalling storeminder-0.1.0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.582155686-05:00 Successfully uninstalled storeminder-0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.691378249-05:00 Successfully installed storeminder-0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.691591308-05:00 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.825911777-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.825956876-05:00 [notice] A new release of pip is available: 24.0 -> 26.1.2 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:40.825962836-05:00 [notice] To update, run: pip install --upgrade pip [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:41.255229442-05:00 Obtaining file:///prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:41.257327110-05:00 Installing build dependencies: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.155399024-05:00 Installing build dependencies: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.156371419-05:00 Checking if build backend supports build_editable: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.265380983-05:00 Checking if build backend supports build_editable: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.266470117-05:00 Getting requirements to build editable: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.428559696-05:00 Getting requirements to build editable: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.429869269-05:00 Preparing editable metadata (pyproject.toml): started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.603441862-05:00 Preparing editable metadata (pyproject.toml): finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.682863736-05:00 Requirement already satisfied: pandas>=1.5.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (3.0.3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.683680252-05:00 Requirement already satisfied: numpy>=1.23.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (2.4.6) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.684532247-05:00 Requirement already satisfied: requests>=2.28.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (2.34.2) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.685222123-05:00 Requirement already satisfied: openpyxl>=3.0.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (3.1.5) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.685968938-05:00 Requirement already satisfied: anthropic>=0.25.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (0.116.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.687220721-05:00 Requirement already satisfied: psycopg>=3.1 in /usr/local/lib/python3.11/site-packages (from psycopg[binary,pool]>=3.1->storeminder==0.1.0) (3.3.4) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.688565023-05:00 Requirement already satisfied: boto3>=1.34 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (1.43.46) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.689263229-05:00 Requirement already satisfied: PyYAML>=6.0 in /usr/local/lib/python3.11/site-packages (from storeminder==0.1.0) (6.0.3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.847760950-05:00 Collecting pytest>=7 (from storeminder==0.1.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.938400059-05:00 Downloading pytest-9.1.1-py3-none-any.whl.metadata (7.6 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.953609402-05:00 Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (4.14.2) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.954809165-05:00 Requirement already satisfied: distro<2,>=1.7.0 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (1.9.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.955803859-05:00 Requirement already satisfied: docstring-parser<1,>=0.15 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (0.18.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.956975843-05:00 Requirement already satisfied: httpx<1,>=0.25.0 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (0.28.1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.958077296-05:00 Requirement already satisfied: jiter<1,>=0.4.0 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (0.16.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.960908240-05:00 Requirement already satisfied: pydantic<3,>=1.9.0 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (2.13.4) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.961622826-05:00 Requirement already satisfied: sniffio in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (1.3.1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.962568360-05:00 Requirement already satisfied: typing-extensions<5,>=4.14 in /usr/local/lib/python3.11/site-packages (from anthropic>=0.25.0->storeminder==0.1.0) (4.16.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.966864046-05:00 Requirement already satisfied: botocore<1.44.0,>=1.43.46 in /usr/local/lib/python3.11/site-packages (from boto3>=1.34->storeminder==0.1.0) (1.43.46) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.967690261-05:00 Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.11/site-packages (from boto3>=1.34->storeminder==0.1.0) (1.1.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.968346417-05:00 Requirement already satisfied: s3transfer<0.20.0,>=0.19.0 in /usr/local/lib/python3.11/site-packages (from boto3>=1.34->storeminder==0.1.0) (0.19.1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:43.970791643-05:00 Requirement already satisfied: et-xmlfile in /usr/local/lib/python3.11/site-packages (from openpyxl>=3.0.0->storeminder==0.1.0) (2.0.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.014940490-05:00 Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas>=1.5.0->storeminder==0.1.0) (2.9.0.post0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.052114636-05:00 Requirement already satisfied: psycopg-binary==3.3.4 in /usr/local/lib/python3.11/site-packages (from psycopg[binary,pool]>=3.1->storeminder==0.1.0) (3.3.4) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.053098981-05:00 Requirement already satisfied: psycopg-pool in /usr/local/lib/python3.11/site-packages (from psycopg[binary,pool]>=3.1->storeminder==0.1.0) (3.3.1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.087821151-05:00 Collecting iniconfig>=1.0.1 (from pytest>=7->storeminder==0.1.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.106622383-05:00 Downloading iniconfig-2.3.0-py3-none-any.whl.metadata (2.5 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.108601482-05:00 Requirement already satisfied: packaging>=22 in /usr/local/lib/python3.11/site-packages (from pytest>=7->storeminder==0.1.0) (26.2) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.139502805-05:00 Collecting pluggy<2,>=1.5 (from pytest>=7->storeminder==0.1.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.155907941-05:00 Downloading pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.158302577-05:00 Requirement already satisfied: pygments>=2.7.2 in /usr/local/lib/python3.11/site-packages (from pytest>=7->storeminder==0.1.0) (2.20.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.165436756-05:00 Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.28.0->storeminder==0.1.0) (3.4.9) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.166333431-05:00 Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.28.0->storeminder==0.1.0) (3.18) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.167125036-05:00 Requirement already satisfied: urllib3<3,>=1.26 in /usr/local/lib/python3.11/site-packages (from requests>=2.28.0->storeminder==0.1.0) (2.7.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.167830232-05:00 Requirement already satisfied: certifi>=2023.5.7 in /usr/local/lib/python3.11/site-packages (from requests>=2.28.0->storeminder==0.1.0) (2026.6.17) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.212512066-05:00 Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.11/site-packages (from httpx<1,>=0.25.0->anthropic>=0.25.0->storeminder==0.1.0) (1.0.9) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.218275833-05:00 Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.11/site-packages (from httpcore==1.*->httpx<1,>=0.25.0->anthropic>=0.25.0->storeminder==0.1.0) (0.16.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.241311370-05:00 Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.11/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.25.0->storeminder==0.1.0) (0.7.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.242148786-05:00 Requirement already satisfied: pydantic-core==2.46.4 in /usr/local/lib/python3.11/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.25.0->storeminder==0.1.0) (2.46.4) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.243279809-05:00 Requirement already satisfied: typing-inspection>=0.4.2 in /usr/local/lib/python3.11/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.25.0->storeminder==0.1.0) (0.4.2) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.253304281-05:00 Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas>=1.5.0->storeminder==0.1.0) (1.17.0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.313736094-05:00 Downloading pytest-9.1.1-py3-none-any.whl (386 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.561753011-05:00 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 386.5/386.5 kB 1.6 MB/s eta 0:00:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.585985872-05:00 Downloading iniconfig-2.3.0-py3-none-any.whl (7.5 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.607596227-05:00 Downloading pluggy-1.6.0-py3-none-any.whl (20 kB) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.619183251-05:00 Checking if build backend supports build_editable: started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.724265248-05:00 Checking if build backend supports build_editable: finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.724875374-05:00 Building wheels for collected packages: storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.725829959-05:00 Building editable for storeminder (pyproject.toml): started [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.893541286-05:00 Building editable for storeminder (pyproject.toml): finished with status 'done' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.894157202-05:00 Created wheel for storeminder: filename=storeminder-0.1.0-0.editable-py3-none-any.whl size=1909 sha256=0d2cba83d2c44a577e998d940100e17e685b6d5a61e6799824c9bb00980e1890 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.894290582-05:00 Stored in directory: /tmp/pip-ephem-wheel-cache-szwmtz_6/wheels/12/13/ba/810e66e2be1a8a55fa7c56f5f12815f8d07be3aad27f734654 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:44.896164471-05:00 Successfully built storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:45.602448216-05:00 Installing collected packages: pluggy, iniconfig, pytest, storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:45.809540297-05:00 Attempting uninstall: storeminder [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:45.847548099-05:00 Found existing installation: storeminder 0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:45.849007690-05:00 Uninstalling storeminder-0.1.0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.001216937-05:00 Successfully uninstalled storeminder-0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.166597167-05:00 Successfully installed iniconfig-2.3.0 pluggy-1.6.0 pytest-9.1.1 storeminder-0.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.166759046-05:00 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.313778502-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.313881272-05:00 [notice] A new release of pip is available: 24.0 -> 26.1.2 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.313888102-05:00 [notice] To update, run: pip install --upgrade pip [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:46.400448415-05:00 INFO[0025] Taking snapshot of full filesystem... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:48.372125134-05:00 INFO[0027] Pushing layer registry.storeminder.ai/images/cache:f5401450489b0f7be50124b33bfa7b0f416eeb2466500d9d7110ce663f2ada42 to cache now [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:48.372272254-05:00 INFO[0027] Pushing image to registry.storeminder.ai/images/cache:f5401450489b0f7be50124b33bfa7b0f416eeb2466500d9d7110ce663f2ada42 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:48.594394738-05:00 INFO[0027] Pushed registry.storeminder.ai/images/cache@sha256:8774537803509aef344c803be4e4d74f3d1992486ac4695ba875d4f8e0b6c3a1 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:48.595062304-05:00 INFO[0027] Pushing image to registry.storeminder.ai/images/storeminder-report-check:pr244-0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-build-pr-image] 2026-07-12T18:10:48.918768276-05:00 INFO[0027] Pushed registry.storeminder.ai/images/storeminder-report-check@sha256:6fff660958af3fd87f552343ed62519fe319a9d4261007848afcc34357ba6cdc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:10:49.866653093-05:00 /tekton/scripts/script-2-jxcrp: line 25: steps.build-pr-image.exitCode.path: command not found [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:10:49.947227740-05:00 job.batch/report-live-pr244-0ebffd8 created [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:18.514327982-05:00 ----- live Job logs (report-live-pr244-0ebffd8) ----- [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035834576-05:00 Running live report trait suite (real Vertex + DB, DRY_RUN): tests/test_report_traits_live.py [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035864515-05:00 ============================= test session starts ============================== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035870015-05:00 platform linux -- Python 3.11.15, pytest-9.1.1, pluggy-1.6.0 -- /usr/local/bin/python [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035875725-05:00 cachedir: .pytest_cache [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035879995-05:00 rootdir: /prsrc [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035885445-05:00 configfile: pyproject.toml [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035889915-05:00 plugins: anyio-4.14.2 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035895545-05:00 collecting ... collected 10 items [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035899705-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035904135-05:00 tests/test_report_traits_live.py::test_daily_builds_and_renders ERROR [ 10%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035908435-05:00 tests/test_report_traits_live.py::test_daily_is_sendable_and_no_weekly_leak ERROR [ 20%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035912665-05:00 tests/test_report_traits_live.py::test_daily_headline_labeled_total_sales ERROR [ 30%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035941355-05:00 tests/test_report_traits_live.py::test_daily_sms_not_truncated ERROR [ 40%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035948945-05:00 tests/test_report_traits_live.py::test_daily_artifact_bundle_written ERROR [ 50%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035953445-05:00 tests/test_report_traits_live.py::test_weekly_builds_and_renders ERROR [ 60%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035957655-05:00 tests/test_report_traits_live.py::test_weekly_is_sendable ERROR [ 70%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035961915-05:00 tests/test_report_traits_live.py::test_weekly_headline_labeled_total_sales ERROR [ 80%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035966125-05:00 tests/test_report_traits_live.py::test_weekly_sms_not_truncated ERROR [ 90%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035970265-05:00 tests/test_report_traits_live.py::test_weekly_artifact_bundle_written ERROR [100%] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035974345-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035978805-05:00 ==================================== ERRORS ==================================== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035983085-05:00 _______________ ERROR at setup of test_daily_builds_and_renders ________________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035987205-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035991495-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.035996305-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036000475-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036004625-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036008695-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036014594-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036020374-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036024754-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036029024-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036033244-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036037504-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036041724-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036045934-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036050134-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036054314-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036058744-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036077664-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036081064-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036083964-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036086854-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036089644-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036092444-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036095314-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036098084-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036101064-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036104004-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036107244-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036110194-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036113524-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036116414-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036121554-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036124674-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036127614-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036135884-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036139004-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036141924-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036144834-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036147744-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036150754-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036160394-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036163244-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036166124-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036169834-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036172774-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036175644-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036178484-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036181374-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036184304-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036187263-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036190133-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036193003-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036197093-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036200833-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036203813-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036206763-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036209633-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036212533-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036215483-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036218443-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036221293-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036224213-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036229113-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036233483-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036236443-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036239333-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036242223-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036246653-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036249523-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036252433-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036255353-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036258353-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036261293-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036264143-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036266983-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036269853-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036272713-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036275643-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036278523-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036281463-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036284313-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036298773-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036301713-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036304533-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036307363-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036310203-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036313103-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036319423-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036322443-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036325603-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036328473-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036331553-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036334363-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036337933-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036340873-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036344173-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036347113-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036349983-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036352843-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036355693-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036358573-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036361402-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036364392-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036367382-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036370232-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036373082-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036375922-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036380202-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036383172-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036386072-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036388972-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036391822-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036394722-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036397532-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036400452-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036403302-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036406202-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036409442-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036417122-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036420072-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036423112-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036425992-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036429722-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036432812-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036435662-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036438672-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036441592-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036444502-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036447492-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036450392-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036453262-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036456132-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036459022-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036461942-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036464832-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036467732-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036470552-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036473442-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036476302-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036479142-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036482002-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036484842-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036487882-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036491402-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036494262-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036497152-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036500032-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036502862-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036505712-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036508592-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036511502-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036514392-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036517252-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036520092-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036523042-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036525902-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036528782-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036531652-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036537451-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036545851-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036548781-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036551641-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036554521-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036557581-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036560431-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036563311-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036566211-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036569021-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036572061-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036574871-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036577681-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036580621-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036583591-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036586551-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036589461-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036592331-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036595201-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036608811-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036611801-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036614751-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036617591-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036620481-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036623311-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036626191-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036629061-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036631881-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036634771-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036637581-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036640601-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036643571-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036646461-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036649411-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036652341-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036655261-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036658171-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036661141-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036668771-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036672581-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036676021-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036678891-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036681831-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036684721-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036687511-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036690351-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036693291-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036696281-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036699121-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036701971-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036704791-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036707621-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036710490-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036713370-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036716210-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036719090-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036722030-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036724890-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036727700-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036730610-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036733520-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036736380-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036742760-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036745720-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036748610-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036751870-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036754720-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036757580-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036760420-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036763240-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036766130-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036769000-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036771840-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036774790-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036777610-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036780450-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036783300-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036791640-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036794650-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036797570-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036800420-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036803240-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036806130-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036808920-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036811810-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036814640-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036817580-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036820450-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036823280-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036826100-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036828940-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036831770-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036834550-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036837390-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036840310-05:00 ---------------------------- Captured stdout setup ----------------------------- [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036843140-05:00 Found 2 XML file(s) in /scratch/v6/Fastime/2026-07-10/raw [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036846140-05:00 Parsed: 2026-07-10.369.xml (966 tx rows, 1940 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036849010-05:00 Parsed: 2026-07-10.527.xml (966 tx rows, 1940 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036851770-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036854580-05:00 Transactions : 966 rows [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036857470-05:00 Date range : 2026-07-09 20:46:32 → 2026-07-10 20:34:48 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036860370-05:00 Types : [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036863280-05:00 Type [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036866160-05:00 sale 618 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036869050-05:00 network sale 277 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036871880-05:00 error_correct 40 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036874740-05:00 safedrop 15 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036877540-05:00 cashier_open 4 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036880350-05:00 cashier_close 4 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036883799-05:00 cashier_audit 4 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036886749-05:00 payout 2 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036889639-05:00 refundevent 1 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036892439-05:00 void 1 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036895159-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036897949-05:00 Scanned items: 1940 rows [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036900769-05:00 Line types : [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036903629-05:00 Line Type [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036906449-05:00 item 1626 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036909319-05:00 fuel 279 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036912109-05:00 merch_code 35 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036914899-05:00 Fuel volume: 2,582.638 gal [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036924259-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036929479-05:00 Saved → /scratch/v6/Fastime/2026-07-10/curated/combined_raw_transactions_20260712_231106.csv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036932409-05:00 Saved → /scratch/v6/Fastime/2026-07-10/curated/combined_raw_scanned_20260712_231106.csv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036935149-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036943479-05:00 ============================================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036946439-05:00 C-Store Analytics — v4 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036949249-05:00 Store: Fastime | Date: 2026-07-10 | Lang: English [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036952119-05:00 ============================================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036954879-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036957729-05:00 📂 [1/10] Loading data... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036961439-05:00 ✓ Loaded 1,940 scan rows | cols: ['time', 'date', 'Type', 'Transaction ID', 'Event Seq ID', 'Store ID', 'Register ID', 'Cashier ID', 'Payment Type', 'Payment Sub Type', 'Source File', 'Line Seq', 'Line Status', 'category', 'UPC Code', 'item', 'Entry Method', 'Merchandise Code', 'Sales Qty', 'Sales UOM', 'amount', 'Regular Price', 'Actual Price', 'Price Override', 'Price Override Reason', 'Promotion ID', 'Promotion Reason', 'Promotion Amount', 'Tax Level', 'Age Restricted', 'Min Age', 'Fuel Grade ID', 'Fuel Position ID', 'Fuel UOM'] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036970669-05:00 ✓ Loaded 966 trans rows | cols: ['Time', 'End Time', 'Business Date', 'Type', 'Transaction ID', 'Event Seq ID', 'Store ID', 'Register ID', 'Cashier ID', 'Till ID', 'Outside Sale', 'Suspended', 'Training Mode', 'Offline', 'Gross Amount', 'Net Amount', 'Tax Amount', 'Total Amount', 'Grand Direction', 'Item Line Count', 'Fuel Line Count', 'Tender Count', 'Tender Type', 'Payment Sub Type', 'Change Amount', 'Void Reason', 'Cash In Drawer', 'Food Stamps', 'Financial Sub-Type', 'Financial Amount', 'Financial Tender', 'Memo', 'Loyalty Discount', 'Loyalty Program', 'Report Seq', 'Report Interval', 'Report Period', 'Report Begin', 'Report End', 'Source File', 'Vendor', 'Vendor Model', 'datetime'] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036973709-05:00 Places hours status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036976679-05:00 ✓ Store hours (Google): 4:00–21:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036979539-05:00 ✓ Scan: 1,940 rows | Trans: 618 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036982349-05:00 ✓ Fuel merged from scan: 2,582.6 gal | $9,446.27 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036985079-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036987889-05:00 📊 [2/10] Loading baseline... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036990759-05:00 ✓ Baseline: 15 same-DOW samples [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036993529-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036996409-05:00 🔍 [3/10] Anomaly detection... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.036999229-05:00 ✓ 18 HIGH / 22 MEDIUM flags [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037001979-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037004809-05:00 🌐 [4/10] External context... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037007619-05:00 Places API (New) status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037010449-05:00 → 5 reviews returned (overall rating 4.3, 532 total ratings on Google) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037013349-05:00 ✓ Reviews: 5 fetched, avg 3.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037016149-05:00 ✓ Weather: Partly cloudy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037019089-05:00 Routes API status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037021929-05:00 ✓ Traffic: Google Routes API (live road traffic) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037024759-05:00 ✓ External: 1634 chars | reviews=5 | traffic=LOW [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037027539-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037030329-05:00 ⛽ [5/10] Fuel Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037033129-05:00 ✓ Fuel section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037035859-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037038689-05:00 💰 [6/10] Fuel Pricing Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037041619-05:00 Fetching competitor fuel prices... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037044659-05:00 → 16 gas stations found with price data [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037047749-05:00 ✓ Fuel pricing section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037050819-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037053859-05:00 🛒 [7/10] Category Management Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037056679-05:00 ✓ Category management section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037106448-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037110648-05:00 🎁 [8/10] Loyalty & Promotions Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037113688-05:00 ✓ Loyalty section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037116498-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037119338-05:00 ⚙️ [9/10] Operations Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037122178-05:00 ✓ Operations section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037124878-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037127698-05:00 📝 [10/10] Synthesis Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037130638-05:00 _________ ERROR at setup of test_daily_is_sendable_and_no_weekly_leak __________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037133388-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037137238-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037140148-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037143078-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037145868-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037148568-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037151468-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037154368-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037157218-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037160198-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037163058-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037165908-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037168728-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037171548-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037174398-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037177208-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037180058-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037182958-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037185778-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037188628-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037191448-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037194428-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037197238-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037200068-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037202838-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037205768-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037208598-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037211518-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037214378-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037217258-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037220148-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037223038-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037234987-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037238087-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037241007-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037243927-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037246827-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037249677-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037252517-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037255347-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037258287-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037261087-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037263927-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037266847-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037269717-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037272587-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037275467-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037278427-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037281337-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037284157-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037287077-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037289937-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037292857-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037295797-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037298787-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037301707-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037304717-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037307577-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037310447-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037313297-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037316157-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037319097-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037327017-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037329897-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037332897-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037335827-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037338677-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037341517-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037344337-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037347227-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037350107-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037352997-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037355937-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037358837-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037361767-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037364617-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037369417-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037372317-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037375267-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037378137-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037381057-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037383917-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037389797-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037392737-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037395767-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037398767-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037401737-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037404657-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037407626-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037410476-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037413296-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037416166-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037418986-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037421876-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037424806-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037427926-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037435896-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037438896-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037441786-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037444666-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037449376-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037452326-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037455286-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037458166-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037461036-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037463866-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037466716-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037469776-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037472646-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037475526-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037478386-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037481346-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037484236-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037487096-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037490046-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037493306-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037496206-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037499076-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037501956-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037504966-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037507806-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037510686-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037513576-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037516416-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037519266-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037522106-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037524996-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037527896-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037530766-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037533646-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037536516-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037539436-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037542326-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037545186-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037548036-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037550936-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037553786-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037556686-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037564186-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037567146-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037569986-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037572806-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037575676-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037578646-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037581525-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037584385-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037587235-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037590135-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037592965-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037595835-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037598695-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037615785-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037628075-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037632005-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037635195-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037638175-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037641405-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037644285-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037647835-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037650755-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037653635-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037657145-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037662165-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037666695-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037671395-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037675805-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037678965-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037686935-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037689985-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037692925-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037695795-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037699155-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037702395-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037705435-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037708325-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037711575-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037723055-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037726135-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037729005-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037732055-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037734895-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037737835-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037740675-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037743555-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037746505-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037749375-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037752215-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037755074-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037757954-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037762544-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037766124-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037769074-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037772344-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037775334-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037778384-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037781404-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037784274-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037787344-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037790284-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037793124-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037795944-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037798874-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037801764-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037805164-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037808034-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037811044-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037813904-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037816754-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037819754-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037822624-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037825484-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037828374-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037831184-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037834104-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037845094-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037848044-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037850934-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037854214-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037857084-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037859924-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037862754-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037865704-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037868544-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037871394-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037874274-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037877114-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037880004-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037882854-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037885724-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037888674-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037891664-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037894754-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037901274-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037904284-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037907304-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037910194-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037913134-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037916074-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037930133-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037937733-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037940703-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037943553-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037946463-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037949303-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037952203-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037955113-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037957983-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037960803-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037963653-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037966503-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037969233-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037972143-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037975133-05:00 __________ ERROR at setup of test_daily_headline_labeled_total_sales ___________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037983543-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037986453-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037989313-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037992233-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037995103-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.037997803-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038000623-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038003513-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038006333-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038009233-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038012133-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038014953-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038017753-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038020683-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038023513-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038026513-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038029433-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038032263-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038035353-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038038203-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038040993-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038043883-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038046693-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038049713-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038052423-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038055303-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038058213-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038061323-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038065223-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038068173-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038072283-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038075573-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038078503-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038081373-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038093553-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038096653-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038099572-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038102532-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038105492-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038108392-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038111592-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038114322-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038118142-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038121692-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038124882-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038127772-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038130762-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038133652-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038136542-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038139392-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038142342-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038145212-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038148082-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038150972-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038153902-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038156742-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038159612-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038162482-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038165332-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038168192-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038171072-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038174002-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038177432-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038180312-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038183232-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038186082-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038188922-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038191772-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038199802-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038202672-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038205722-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038208632-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038211582-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038214402-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038217322-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038220252-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038223072-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038226702-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038229652-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038232652-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038235542-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038238502-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038241362-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038244222-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038247042-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038249882-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038252772-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038258492-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038261502-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038264372-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038267201-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038270101-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038272901-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038275791-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038278721-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038282041-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038284961-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038288551-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038291481-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038294891-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038297891-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038300851-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038303781-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038311461-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038314461-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038317381-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038320231-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038323161-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038326151-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038329021-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038331921-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038334761-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038337621-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038340451-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038343291-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038346151-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038349011-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038351961-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038354821-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038357691-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038360531-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038363381-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038366391-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038369241-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038372121-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038375021-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038377911-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038380821-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038383691-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038386591-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038389471-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038392381-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038395251-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038398111-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038401601-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038404451-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038407351-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038410381-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038413241-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038416091-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038419141-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038422061-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038424931-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038427801-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038435300-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038438250-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038441120-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038443980-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038446850-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038449760-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038452650-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038455470-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038458940-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038461840-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038464790-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038467770-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038470740-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038473680-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038479230-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038482230-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038485110-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038487990-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038490810-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038493690-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038496620-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038499470-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038502280-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038505080-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038507910-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038510880-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038513760-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038516780-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038519700-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038522560-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038525460-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038528250-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038531130-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038533960-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038536820-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038539680-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038542570-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038545390-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038548250-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038556120-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038559010-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038561940-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038565630-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038568620-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038571480-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038574350-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038577210-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038580090-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038582920-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038585880-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038588720-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038591660-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038594570-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038597440-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038600310-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038603179-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038606059-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038608939-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038611769-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038614589-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038617479-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038620259-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038623659-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038626519-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038629529-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038632339-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038635159-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038638079-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038640979-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038643839-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038646709-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038649549-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038652399-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038655319-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038658279-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038661149-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038671429-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038674389-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038677369-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038680199-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038683029-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038685869-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038688749-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038691599-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038694419-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038697309-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038700119-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038702979-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038705789-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038708629-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038711519-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038714439-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038717269-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038720149-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038722969-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038725909-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038729079-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038731889-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038734699-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038737649-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038740459-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038743329-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038746169-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038749039-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038752459-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038755309-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038758099-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038760979-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038763809-05:00 ________________ ERROR at setup of test_daily_sms_not_truncated ________________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038766519-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038769319-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038772188-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038775018-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038777878-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038780598-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038783528-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038786428-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038790038-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038797928-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038801298-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038804218-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038807068-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038809898-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038813368-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038816358-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038819188-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038821988-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038824818-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038828588-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038831428-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038834368-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038837238-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038840188-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038842948-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038845828-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038848718-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038852048-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038854998-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038857908-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038860858-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038863888-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038869328-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038872318-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038875238-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038878118-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038880918-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038888758-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038891608-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038894438-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038897398-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038900188-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038902998-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038905798-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038908718-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038911588-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038914438-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038924258-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038929278-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038932178-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038935128-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038937938-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038940907-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038943817-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038946727-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038949647-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038952487-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038955367-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038958187-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038961027-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038963877-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038966767-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038969687-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038972557-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038975377-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038978887-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038981837-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038984737-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038987627-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038990567-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038993467-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038996407-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.038999357-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039002277-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039005197-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039013867-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039016797-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039019707-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039022577-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039025397-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039028217-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039031087-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039036897-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039039847-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039042797-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039045737-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039048547-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039051417-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039054237-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039057047-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039059927-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039062747-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039065637-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039068567-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039071437-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039074437-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039077277-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039080197-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039083057-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039085957-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039088867-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039091717-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039094637-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039097467-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039100377-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039103217-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039106087-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039108977-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039111957-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039114806-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039117646-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039125396-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039128686-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039131516-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039134416-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039137296-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039140196-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039143036-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039145916-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039148786-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039151616-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039154496-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039157426-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039160286-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039163236-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039166076-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039168916-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039171716-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039174516-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039177376-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039180256-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039183106-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039186036-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039189216-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039192036-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039194846-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039197646-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039200546-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039203356-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039206186-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039209136-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039211986-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039214836-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039217706-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039220526-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039223416-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039226316-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039229126-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039232086-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039234976-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039237806-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039253916-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039274266-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039278356-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039281636-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039284876-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039288536-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039291365-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039294595-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039297575-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039305965-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039308985-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039312495-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039315375-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039318565-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039321455-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039324305-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039327105-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039330035-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039332945-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039335885-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039341315-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039345055-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039348005-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039350815-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039353765-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039356665-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039359465-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039362465-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039365235-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039368015-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039370815-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039374305-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039377175-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039380005-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039382945-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039385825-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039388845-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039391965-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039394825-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039404475-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039407395-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039411515-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039414485-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039417415-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039420315-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039423155-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039426055-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039428865-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039431835-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039434655-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039437525-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039440495-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039443345-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039446145-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039448945-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039451765-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039454555-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039458395-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039461265-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039464174-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039467034-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039469864-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039472804-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039475624-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039478504-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039481534-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039484644-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039487524-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039490344-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039493174-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039496044-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039502204-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039505134-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039507974-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039510894-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039513804-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039522554-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039525474-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039528304-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039531154-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039534044-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039536914-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039539834-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039542714-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039545654-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039548524-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039551394-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039554324-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039557834-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039560754-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039563644-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039567274-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039570164-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039573014-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039575834-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039578714-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039581604-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039584454-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039587374-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039590154-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039593044-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039595894-05:00 _____________ ERROR at setup of test_daily_artifact_bundle_written _____________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039598634-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039601514-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039604354-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039607144-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039610064-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039612794-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039616114-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039618974-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039622064-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039624904-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039627714-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039630754-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039634424-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039637314-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039640173-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039643063-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039651333-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039654203-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039657063-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039659803-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039662723-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039665503-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039668283-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039671123-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039673823-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039676733-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039679643-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039682873-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039685793-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039688873-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039692403-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039696363-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039699253-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039705083-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039708183-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039711123-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039714033-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039716973-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039720773-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039723763-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039732013-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039734783-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039737683-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039740653-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039743543-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039746393-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039749273-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039752713-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039755583-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039758423-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039761273-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039764263-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039767103-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039769963-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039774203-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039777833-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039780733-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039783563-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039786403-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039789663-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039792533-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039795423-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039798323-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039801133-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039803973-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039808233-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039812722-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039817342-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039821722-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039826272-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039830212-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039833102-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039835992-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039838832-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039841712-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039844662-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039848022-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039850902-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039853782-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039856622-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039864762-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039867622-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039870502-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039873412-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039876302-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039882822-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039885812-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039888912-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039891782-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039894612-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039897492-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039900352-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039903242-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039906132-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039909042-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039912662-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039915512-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039965192-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039974132-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039977092-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039980552-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039983472-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039986342-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039989171-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039992301-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039995161-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.039998111-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040000991-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040004201-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040007101-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040009971-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040012791-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040015651-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040018531-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040021421-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040024351-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040027321-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040030171-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040039141-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040042051-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040044951-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040047881-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040050811-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040053641-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040056561-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040059451-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040062371-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040065221-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040068061-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040071031-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040073921-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040076861-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040079811-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040082671-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040085561-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040088421-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040091271-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040094161-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040097061-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040099911-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040102751-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040105611-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040108501-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040111401-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040114241-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040117051-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040119951-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040122751-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040125691-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040128481-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040131311-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040134191-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040137051-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040139931-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040142881-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040145831-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040152751-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040155771-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040163860-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040166880-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040169820-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040172780-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040175610-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040178460-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040181330-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040184190-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040187040-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040189830-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040192650-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040195540-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040198370-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040201270-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040204180-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040207030-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040209910-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040212760-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040215560-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040218550-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040221430-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040224310-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040227200-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040230150-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040233040-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040235920-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040238750-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040241660-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040244490-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040247360-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040250220-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040253080-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040255960-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040258840-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040261760-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040264640-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040267470-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040270420-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040277900-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040280780-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040283610-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040286460-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040289290-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040292170-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040294990-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040297840-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040300720-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040303520-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040306320-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040309140-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040311970-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040314910-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040317770-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040320620-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040324530-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040327460-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040330400-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040333280-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040336169-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040341849-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040344779-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040347769-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040350729-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040353609-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040356729-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040359559-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040362619-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040365609-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040368499-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040371419-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040374309-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040377149-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040379999-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040382909-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040385789-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040388729-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040391589-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040399809-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040402669-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040405579-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040408389-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040411279-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040414189-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040417039-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040419839-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040422669-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040425469-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040428299-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040431229-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040434059-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040436929-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040439749-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040442469-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040445349-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040448169-05:00 _______________ ERROR at setup of test_weekly_builds_and_renders _______________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040450909-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040453709-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040456529-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040460129-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040462989-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040465709-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040468549-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040471489-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040474349-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040477199-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040480039-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040482979-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040485789-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040488609-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040492149-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040494459-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040497409-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040499729-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040501979-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040504869-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040507129-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040509349-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040511638-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040513898-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040520288-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040522578-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040524898-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040527328-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040529678-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040531938-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040534248-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040538958-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040541408-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040543798-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040546288-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040548628-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040550978-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040553298-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040555568-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040557808-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040560048-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040562358-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040564588-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040566798-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040569068-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040575338-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040577668-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040579928-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040582228-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040584798-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040587138-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040589528-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040591858-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040594188-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040596478-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040598748-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040601028-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040603298-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040605638-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040607958-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040610278-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040612538-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040614838-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040617108-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040619368-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040622148-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040624478-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040627238-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040629618-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040631928-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040634198-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040636538-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040638788-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040641038-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040643478-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040645788-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040650518-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040652828-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040655128-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040657508-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040659828-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040662128-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040664388-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040666628-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040668928-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040675138-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040677418-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040679658-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040681898-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040684267-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040687117-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040689457-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040691737-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040694077-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040696377-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040698657-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040701827-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040704167-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040706447-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040708747-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040711487-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040714207-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040716487-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040718747-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040721017-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040723417-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040725727-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040727977-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040730267-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040732537-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040734817-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040737137-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040739417-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040741727-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040743967-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040746217-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040748467-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040750757-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040753117-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040755447-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040757707-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040760047-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040762337-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040764637-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040770697-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040772987-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040775257-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040777497-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040779777-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040782087-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040784377-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040786647-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040788927-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040791307-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040794067-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040797417-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040799747-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040802117-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040805637-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040807957-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040810267-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040812537-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040814787-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040828097-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040836247-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040840347-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040844317-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040847277-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040850397-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040853307-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040861376-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040864526-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040867636-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040871346-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040874256-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040877186-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040880086-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040882966-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040885876-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040888816-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040891626-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040894516-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040897316-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040908616-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040911596-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040914426-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040924916-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040933446-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040937026-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040939866-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040942686-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040945606-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040948686-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040951706-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040954626-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040957526-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040961006-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040963936-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040966736-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040969536-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040972316-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040975116-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040977946-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040980876-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040983666-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040986486-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040989346-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040993286-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040996216-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.040999056-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041001966-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041004936-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041007746-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041010696-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041013666-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041016566-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041019476-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041022316-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041025176-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041028116-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041037415-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041040265-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041043215-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041045985-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041048935-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041051795-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041054575-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041057495-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041060425-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041063235-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041066255-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041072925-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041075915-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041078805-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041081725-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041084615-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041087495-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041090395-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041093715-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041097255-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041100205-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041103085-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041105955-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041108865-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041111695-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041114635-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041117525-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041120385-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041123185-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041126105-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041129065-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041132545-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041136825-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041139785-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041142695-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041145585-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041148455-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041151245-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041154165-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041161935-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041164805-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041167625-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041170555-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041173365-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041176245-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041179135-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041182005-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041184875-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041187695-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041191135-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041194035-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041196775-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041199665-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041202545-05:00 ---------------------------- Captured stdout setup ----------------------------- [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041205375-05:00 Found 14 XML file(s) in /scratch/v6/Fastime/2026-07-10/raw [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041208194-05:00 Parsed: 2026-07-04.363.xml (460 tx rows, 810 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041210964-05:00 Parsed: 2026-07-04.521.xml (460 tx rows, 810 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041213734-05:00 Parsed: 2026-07-05.364.xml (442 tx rows, 789 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041216514-05:00 Parsed: 2026-07-05.522.xml (442 tx rows, 789 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041219284-05:00 Parsed: 2026-07-06.365.xml (853 tx rows, 1623 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041222044-05:00 Parsed: 2026-07-06.523.xml (853 tx rows, 1623 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041225354-05:00 Parsed: 2026-07-07.366.xml (873 tx rows, 1716 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041228284-05:00 Parsed: 2026-07-07.524.xml (873 tx rows, 1716 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041231124-05:00 Parsed: 2026-07-08.367.xml (953 tx rows, 1837 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041233924-05:00 Parsed: 2026-07-08.525.xml (953 tx rows, 1837 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041236714-05:00 Parsed: 2026-07-09.368.xml (958 tx rows, 1876 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041239554-05:00 Parsed: 2026-07-09.526.xml (958 tx rows, 1876 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041242344-05:00 Parsed: 2026-07-10.369.xml (966 tx rows, 1940 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041245134-05:00 Parsed: 2026-07-10.527.xml (966 tx rows, 1940 scan rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041247824-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041250744-05:00 Transactions : 5505 rows [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041253584-05:00 Date range : 2026-07-03 19:56:24 → 2026-07-10 20:34:48 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041256434-05:00 Types : [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041259264-05:00 Type [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041262084-05:00 sale 3542 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041264884-05:00 network sale 1572 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041267694-05:00 error_correct 233 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041271114-05:00 safedrop 67 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041273954-05:00 cashier_open 20 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041276744-05:00 cashier_close 20 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041279514-05:00 void 19 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041282294-05:00 cashier_audit 19 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041285114-05:00 payout 11 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041292524-05:00 refundevent 2 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041295264-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041298104-05:00 Scanned items: 10591 rows [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041300954-05:00 Line types : [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041303754-05:00 Line Type [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041306544-05:00 item 8891 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041309344-05:00 fuel 1583 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041312124-05:00 merch_code 117 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041314884-05:00 Fuel volume: 15,703.814 gal [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041317554-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041320404-05:00 Saved → /scratch/v6/Fastime/2026-07-10/curated/combined_raw_transactions_20260712_231237.csv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041323334-05:00 Saved → /scratch/v6/Fastime/2026-07-10/curated/combined_raw_scanned_20260712_231237.csv [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041326084-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041331624-05:00 ============================================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041334554-05:00 C-Store Analytics — v4 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041337414-05:00 Store: Fastime | Date: 2026-07-10 | Lang: English [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041340304-05:00 ============================================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041343024-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041345894-05:00 📂 [1/10] Loading data... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041349324-05:00 ✓ Loaded 10,591 scan rows | cols: ['time', 'date', 'Type', 'Transaction ID', 'Event Seq ID', 'Store ID', 'Register ID', 'Cashier ID', 'Payment Type', 'Payment Sub Type', 'Source File', 'Line Seq', 'Line Status', 'category', 'UPC Code', 'item', 'Entry Method', 'Merchandise Code', 'Sales Qty', 'Sales UOM', 'amount', 'Regular Price', 'Actual Price', 'Price Override', 'Price Override Reason', 'Promotion ID', 'Promotion Reason', 'Promotion Amount', 'Tax Level', 'Age Restricted', 'Min Age', 'Fuel Grade ID', 'Fuel Position ID', 'Fuel UOM'] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041352574-05:00 ✓ Loaded 5,505 trans rows | cols: ['Time', 'End Time', 'Business Date', 'Type', 'Transaction ID', 'Event Seq ID', 'Store ID', 'Register ID', 'Cashier ID', 'Till ID', 'Outside Sale', 'Suspended', 'Training Mode', 'Offline', 'Gross Amount', 'Net Amount', 'Tax Amount', 'Total Amount', 'Grand Direction', 'Item Line Count', 'Fuel Line Count', 'Tender Count', 'Tender Type', 'Payment Sub Type', 'Change Amount', 'Void Reason', 'Cash In Drawer', 'Food Stamps', 'Financial Sub-Type', 'Financial Amount', 'Financial Tender', 'Memo', 'Loyalty Discount', 'Loyalty Program', 'Report Seq', 'Report Interval', 'Report Period', 'Report Begin', 'Report End', 'Source File', 'Vendor', 'Vendor Model', 'datetime'] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041355494-05:00 Places hours status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041359094-05:00 ✓ Store hours (Google): 4:00–21:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041361984-05:00 ✓ Scan: 1,940 rows | Trans: 618 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041364764-05:00 ✓ Fuel merged from scan: 2,582.6 gal | $9,446.27 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041367464-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041370414-05:00 📊 [2/10] Loading baseline... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041373244-05:00 ✓ Baseline: 15 same-DOW samples [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041375954-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041378744-05:00 🔍 [3/10] Anomaly detection... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041381594-05:00 ✓ 18 HIGH / 22 MEDIUM flags [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041384293-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041387083-05:00 🌐 [4/10] External context... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041389893-05:00 Places API (New) status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041392823-05:00 → 5 reviews returned (overall rating 4.3, 532 total ratings on Google) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041395713-05:00 ✓ Reviews: 5 fetched, avg 3.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041398493-05:00 ✓ Weather: Clear [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041401293-05:00 Routes API status: 200 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041411723-05:00 ✓ Traffic: Google Routes API (live road traffic) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041414583-05:00 ✓ External: 1740 chars | reviews=5 | traffic=LOW [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041417293-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041420073-05:00 ⛽ [5/10] Fuel Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041422973-05:00 ✓ Fuel section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041425683-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041428453-05:00 💰 [6/10] Fuel Pricing Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041431253-05:00 Fetching competitor fuel prices... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041434073-05:00 → 16 gas stations found with price data [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041436843-05:00 ✓ Fuel pricing section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041439563-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041442353-05:00 🛒 [7/10] Category Management Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041445203-05:00 ✓ Category management section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041447903-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041450663-05:00 🎁 [8/10] Loyalty & Promotions Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041453533-05:00 ✓ Loyalty section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041456233-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041459023-05:00 ⚙️ [9/10] Operations Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041461893-05:00 ✓ Operations section written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041464743-05:00 📅 Generating schedule optimisation... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041467623-05:00 ✓ Weekly per-day breakdown: 7 trading day(s) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041470483-05:00 ✓ Weekly baseline: summed across 7 day(s) (totals scaled, ratios recomputed) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041473173-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041475963-05:00 📝 [10/10] Synthesis Agent... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041478853-05:00 __________________ ERROR at setup of test_weekly_is_sendable ___________________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041481573-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041484343-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041487143-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041490003-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041492823-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041495513-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041498323-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041501193-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041504073-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041506883-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041509703-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041512563-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041515343-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041518533-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041521303-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041524123-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041526923-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041529713-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041532473-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041535323-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041538133-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041540993-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041543783-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041546603-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041549333-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041556332-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041559262-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041565412-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041568452-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041571462-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041574622-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041577462-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041580532-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041584832-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041587792-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041590732-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041593552-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041596452-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041599332-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041602142-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041605002-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041608122-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041610882-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041613722-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041616572-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041619412-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041627512-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041630412-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041633232-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041636042-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041638952-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041641802-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041644852-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041647722-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041650582-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041653392-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041656222-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041659222-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041662052-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041664892-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041667712-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041670552-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041673392-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041676322-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041679112-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041681912-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041684742-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041692182-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041695652-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041700052-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041704262-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041708802-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041712862-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041717592-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041720452-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041723262-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041726162-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041728942-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041731761-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041734601-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041737441-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041740711-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041743501-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041746291-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041749111-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041757101-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041760001-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041762881-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041765701-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041768591-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041771431-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041774241-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041777871-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041780711-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041783591-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041786481-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041789721-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041792631-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041795461-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041798341-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041801221-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041804041-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041807111-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041809951-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041812781-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041815651-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041818471-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041821301-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041824151-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041827041-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041829941-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041832741-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041835571-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041838481-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041841361-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041844191-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041847021-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041849861-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041852691-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041855511-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041858321-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041861191-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041864051-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041866921-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041874291-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041877191-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041880011-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041882841-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041885651-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041888511-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041894991-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041897911-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041900851-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041903701-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041906550-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041909580-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041912610-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041915410-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041930260-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041935740-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041938650-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041941430-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041944300-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041947410-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041950350-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041953230-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041956080-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041958900-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041961770-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041964910-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041967720-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041970540-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041973370-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041976230-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041979050-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041981870-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041984770-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041987640-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041990850-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041993640-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041996560-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.041999360-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042002150-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042005120-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042015960-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042018860-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042021770-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042024580-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042027450-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042030300-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042033120-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042035950-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042038820-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042041670-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042044490-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042047880-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042050770-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042053720-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042056570-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042059340-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042062090-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042064910-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042067770-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042070660-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042073520-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042076390-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042079260-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042082059-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042084869-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042087719-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042090519-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042093329-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042096179-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042099109-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042101969-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042104799-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042111139-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042114119-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042117059-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042120049-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042122949-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042130739-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042133599-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042136539-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042139369-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042142209-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042144979-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042147809-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042150669-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042153489-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042156359-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042159829-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042162639-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042165429-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042168239-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042171079-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042173889-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042176669-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042179529-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042182329-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042185199-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042188009-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042190809-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042193759-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042196579-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042199379-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042202189-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042204989-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042207859-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042210649-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042213479-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042216329-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042219129-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042221989-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042224779-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042227639-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042230439-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042233989-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042236799-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042239669-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042247619-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042250479-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042253269-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042256108-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042258998-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042261828-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042264648-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042267488-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042270278-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042273158-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042276018-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042278728-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042281618-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042284448-05:00 __________ ERROR at setup of test_weekly_headline_labeled_total_sales __________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042287188-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042290008-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042292808-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042295628-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042298418-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042301118-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042304008-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042306858-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042309698-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042312548-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042315448-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042321068-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042324028-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042326898-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042329778-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042332588-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042335538-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042338398-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042341208-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042344088-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042346918-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042349788-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042352678-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042355578-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042358388-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042361208-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042364098-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042366958-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042374578-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042378148-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042381038-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042383898-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042386868-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042389718-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042392578-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042395428-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042398248-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042401088-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042404018-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042406888-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042409868-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042413238-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042415978-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042418778-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042421598-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042424438-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042427298-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042430777-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042433717-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042436537-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042444357-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042447237-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042450087-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042463537-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042472247-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042475477-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042477757-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042480027-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042482287-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042484537-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042487247-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042490007-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042498277-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042501147-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042504877-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042508137-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042512237-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042516977-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042521327-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042525657-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042530257-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042533067-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042535867-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042538757-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042541527-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042544277-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042546977-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042549757-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042552527-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042555277-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042557997-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042560787-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042565257-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042568077-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042570847-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042573577-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042576377-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042579167-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042590317-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042593227-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042596477-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042599177-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042601877-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042604576-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042607386-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042610246-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042613166-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042615966-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042618786-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042621516-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042624266-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042627006-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042629826-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042632566-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042635316-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042638096-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042640826-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042643546-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042646476-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042649406-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042652436-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042655176-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042658816-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042661626-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042664476-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042667236-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042670136-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042672956-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042675836-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042678596-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042681306-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042684086-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042686886-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042689866-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042692786-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042695936-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042702776-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042705626-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042713786-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042716706-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042719566-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042722396-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042725236-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042728036-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042730786-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042733516-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042736236-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042738996-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042742896-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042745766-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042748486-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042751256-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042753976-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042756816-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042759506-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042762236-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042764936-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042767636-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042770386-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042773176-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042775976-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042778705-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042781465-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042784175-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042786885-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042789745-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042792515-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042795305-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042798065-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042800775-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042803535-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042806235-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042808895-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042811715-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042814415-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042817235-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042820605-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042828265-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042831065-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042833815-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042836575-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042839295-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042842135-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042845025-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042847815-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042850515-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042853335-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042856135-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042858865-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042861695-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042864415-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042867245-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042870095-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042872925-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042875615-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042878365-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042881095-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042883805-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042886515-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042889275-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042891965-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042894665-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042897355-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042900185-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042906065-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042908885-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042911745-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042916145-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042924935-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042931825-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042934615-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042937415-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042940125-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042942815-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042950805-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042953654-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042956414-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042959774-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042962634-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042965404-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042968184-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042970934-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042973784-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042976524-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042979224-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042982034-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042984724-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042987444-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042990214-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042992904-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042995674-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.042998424-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043001914-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043004714-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043007424-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043010164-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043012874-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043015614-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043018394-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043021094-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043023834-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043026644-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043030234-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043033194-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043035944-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043038954-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043041734-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043044484-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043047254-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043050104-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043052974-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043055944-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043058804-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043066284-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043069064-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043071754-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043075194-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043077984-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043080714-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043083484-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043086374-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043089144-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043092114-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043094914-05:00 _______________ ERROR at setup of test_weekly_sms_not_truncated ________________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043097634-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043100424-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043103154-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043105884-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043108594-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043111194-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043113974-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043116924-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043119734-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043122504-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043128513-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043131313-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043134073-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043136923-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043139693-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043142453-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043145183-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043147913-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043150633-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043153393-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043156073-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043158893-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043161583-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043164373-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043167003-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043169873-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043172803-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043175703-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043178543-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043181443-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043184313-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043191783-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043194703-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043197683-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043200623-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043203483-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043206593-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043209433-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043212193-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043214893-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043217613-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043220483-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043223083-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043225963-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043228793-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043231753-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043234583-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043237783-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043240523-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043243313-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043248743-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043251633-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043254383-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043257143-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043264553-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043267373-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043270213-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043273103-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043275933-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043278943-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043281863-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043284733-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043287433-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043290213-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043292933-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043295643-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043298343-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043301072-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043303832-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043306532-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043309262-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043311992-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043315382-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043318182-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043320942-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043323632-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043326492-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043329282-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043332012-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043334782-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043337552-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043340302-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043343002-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043345702-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043348502-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043351182-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043353892-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043356582-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043359302-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043362112-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043364832-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043372012-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043374782-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043377522-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043380272-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043382992-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043385862-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043388622-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043391342-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043394052-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043396842-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043399562-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043402312-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043405022-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043407782-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043410552-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043413242-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043415942-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043418742-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043421522-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043424452-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043427352-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043430082-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043432862-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043435742-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043438572-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043441412-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043446642-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043449452-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043452302-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043454982-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043457802-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043460522-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043463382-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043466122-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043468872-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043471612-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043474332-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043477951-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043480801-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043483751-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043490161-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043492381-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043494721-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043497041-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043499471-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043502971-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043505891-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043508221-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043510481-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043512641-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043514821-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043517051-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043519301-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043521521-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043523681-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043525871-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043528121-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043530881-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043533091-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043535261-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043537481-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043539651-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043541831-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043544151-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043546481-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043548831-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043551161-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043553361-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043555631-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043557791-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043560001-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043562691-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043564971-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043567131-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043569311-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043571541-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043573851-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043576151-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043578441-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043587461-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043589821-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043592551-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043594771-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043596971-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043599241-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043602331-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043604581-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043606841-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043609131-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043611381-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043613671-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043616001-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043618191-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043620371-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043624741-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043627611-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043629791-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043632091-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043634411-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043636601-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043638751-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043640931-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043643181-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043645501-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043647701-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043649950-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043652200-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043654910-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043657120-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043659360-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043661620-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043663920-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043666280-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043669050-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043671390-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043673650-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043679780-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043682190-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043684510-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043687310-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043690070-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043692260-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043694460-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043696680-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043698950-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043701370-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043703660-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043706100-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043708380-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043710640-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043712890-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043715610-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043717820-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043720030-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043722280-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043724600-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043726840-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043729080-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043731320-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043733540-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043735730-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043737920-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043740750-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043742960-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043745140-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043747340-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043749540-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043751800-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043753990-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043756210-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043758390-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043760650-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043762820-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043765010-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043767190-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043769370-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043775550-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043778420-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043780640-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043784960-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043787110-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043789370-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043791620-05:00 ____________ ERROR at setup of test_weekly_artifact_bundle_written _____________ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043793780-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043795960-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043798160-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043800410-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043802710-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043804800-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043807040-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043809300-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043811500-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043813700-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043815880-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043818110-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043820300-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043822500-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043824699-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043826899-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043829079-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043831259-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043833439-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043835749-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043837969-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043840309-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043842689-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043844869-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043846989-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043849219-05:00 self = [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043851419-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043853749-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043856039-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043858259-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043860469-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043862729-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043868739-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043870959-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043873159-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043875449-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043877759-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043879959-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043882159-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043898719-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043907539-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043931079-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043939309-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043943449-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043947979-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043953729-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043957929-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043962179-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043966229-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043970389-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043974519-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043978499-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043982489-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043986689-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043990649-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043994559-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.043998468-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044002648-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044006598-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044020238-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044024328-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044028308-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044032218-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044036118-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044040118-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044044158-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044048178-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044052238-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044056198-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044060078-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044064048-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044067948-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044072068-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044076308-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044080968-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044085538-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044089848-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044094088-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044098438-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044102628-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044106808-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044111328-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044115418-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044119398-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044123638-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044127728-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044132008-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044136368-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044140468-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044144738-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044150078-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044155278-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044160068-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044164147-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044178497-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044182857-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044188117-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044192287-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044196627-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044200697-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044205227-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044209497-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044213707-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044217827-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044221937-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044233137-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044237667-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044241727-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044245987-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044250377-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044254457-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044258667-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044263007-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044267117-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044271327-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044275667-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044280067-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044284617-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044289527-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044294117-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044298467-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044302817-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044307087-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044311167-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044315637-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044319567-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044323517-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044327587-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044331687-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044335516-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044339836-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044344026-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044348226-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044352386-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044356766-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044360936-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044374076-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044378746-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044383386-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044387926-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044392306-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044396636-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044401186-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044405596-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044409946-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044414396-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044418776-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044423246-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044427656-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044432286-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044436676-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044440866-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044445446-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044449746-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044454626-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044459386-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044463926-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044468486-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044472856-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044477506-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044481956-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044486356-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044490876-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044495106-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044499506-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044503955-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044508285-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044512165-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044516335-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044520755-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044525555-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044529915-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044534355-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044538865-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044552225-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044557115-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044569395-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044574075-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044577265-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044580115-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044583035-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044585885-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044588755-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044591765-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044594625-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044597455-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044600385-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044603245-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044606145-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044609335-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044612255-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044616325-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044620725-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044625435-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044630095-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044635085-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044640185-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044644545-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044649265-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044653735-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044658445-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044663015-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044667085-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044669954-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044672754-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044675604-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044678484-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044681414-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044684304-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044687114-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044689974-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044692924-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044702704-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044706704-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044709844-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044712784-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044715704-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044719344-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044722204-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044725074-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044727904-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044730754-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044733714-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044736674-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044739574-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044742424-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044745404-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044748714-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044751504-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044754364-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044757344-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044760224-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044763204-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044767814-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044770754-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044773724-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044776764-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044779804-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044782904-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044785974-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044788864-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044797484-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044800454-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044803344-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044806254-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044809144-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044812124-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044815254-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044818134-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044820934-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044823834-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044833854-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044836804-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044839733-05:00 --------------------- generated xml file: /tmp/traits.xml ---------------------- [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044842753-05:00 =========================== short test summary info ============================ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044845983-05:00 ERROR tests/test_report_traits_live.py::test_daily_builds_and_renders - Attri... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044848853-05:00 ERROR tests/test_report_traits_live.py::test_daily_is_sendable_and_no_weekly_leak [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044851723-05:00 ERROR tests/test_report_traits_live.py::test_daily_headline_labeled_total_sales [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044854613-05:00 ERROR tests/test_report_traits_live.py::test_daily_sms_not_truncated - Attrib... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044857613-05:00 ERROR tests/test_report_traits_live.py::test_daily_artifact_bundle_written - ... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044860493-05:00 ERROR tests/test_report_traits_live.py::test_weekly_builds_and_renders - Attr... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044863363-05:00 ERROR tests/test_report_traits_live.py::test_weekly_is_sendable - AttributeEr... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044866333-05:00 ERROR tests/test_report_traits_live.py::test_weekly_headline_labeled_total_sales [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044869333-05:00 ERROR tests/test_report_traits_live.py::test_weekly_sms_not_truncated - Attri... [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044872233-05:00 ERROR tests/test_report_traits_live.py::test_weekly_artifact_bundle_written [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044875113-05:00 ======================== 10 errors in 130.27s (0:02:10) ======================== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044877963-05:00 ===JUNIT_BEGIN=== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044881393-05:00 @pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044884283-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044887173-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044890053-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044892803-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044895653-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044898573-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044901433-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044904283-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044907203-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044910693-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044913683-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044916623-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044930693-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044933633-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044936463-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044939513-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044942353-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044945453-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044948413-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044956583-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044959463-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044962893-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044965623-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044968803-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x751542f9ca50> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044971703-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044975063-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044977973-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044980853-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044983733-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044991623-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044994793-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.044997763-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045000643-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045003563-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045006423-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045009262-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045012152-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045015012-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045017872-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045020632-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045024252-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045027272-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045034952-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045037812-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045040662-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045043502-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045046312-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045049152-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045052022-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045054902-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045057852-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045060742-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045063682-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045066632-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045069502-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045072352-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045075932-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045078872-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045081762-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045084632-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045087482-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045090382-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045093232-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045096062-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045098942-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045101852-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045104692-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045107522-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045110402-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045113322-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045116312-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045119142-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045121972-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045124872-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045127712-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045130552-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045133442-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045139202-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045142212-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045145142-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045148052-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045156442-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045159352-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045162202-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045165032-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045167892-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045170712-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045173482-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045176322-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045179162-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045181942-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045184781-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045187631-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045190531-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045193401-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045196251-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045199171-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045202021-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045205411-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045208521-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045211351-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045214231-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045217041-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045219931-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045222821-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045225771-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045228581-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045231431-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045234221-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045237031-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045239821-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045242631-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045245511-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045248331-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045251201-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045254081-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045257011-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045259961-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045262831-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045265691-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045268941-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045276631-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045279491-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045282331-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045285231-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045288081-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045290921-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045293831-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045298541-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045301441-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045304381-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045307261-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045310121-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045313031-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045315821-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045318681-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045321561-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045324401-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045327211-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045330031-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045332961-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045335981-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045339461-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045345221-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045348181-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045351081-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045354011-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045356861-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045359760-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045362790-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045365710-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045368690-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045371610-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045375140-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045378140-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045381020-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045383840-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045386660-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045389910-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045392830-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045400470-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045403390-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045406250-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045409120-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045411990-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045414820-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045417630-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045420550-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045423450-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045426350-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045429320-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045433010-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045435890-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045438780-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045441610-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045444540-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045448250-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045451150-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045453950-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045456860-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045459710-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045462570-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045465810-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045468830-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045471810-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045474680-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045477570-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045480550-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045483520-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045486410-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045489260-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045492220-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045495260-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045498170-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045501090-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045504960-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045507810-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045516700-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045519610-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045522540-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045525480-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045528420-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045531270-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045534219-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045537269-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045543129-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045546409-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045549449-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045552389-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045555259-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045558109-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045561009-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045563829-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045566699-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045569559-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045572429-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045575369-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045578179-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045581199-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045583999-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045586839-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045589659-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045592509-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045595339-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045598159-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045600939-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045603779-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045606619-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045609419-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045612269-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045615139-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045617929-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045620839-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045623649-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045628079-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045630949-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045639859-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045643219-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045646089-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045648939-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045651879-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045654779-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045657669-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045660489-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045663459-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045666299-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045669229-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045672209-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045674949-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045679129-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045682049-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045684919-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045687809-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045690549-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045693409-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045696269-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045699119-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045701989-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045705579-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045708458-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045711308-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045714108-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045717028-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045719818-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045722688-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045725468-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045728258-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045731038-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045733818-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045736618-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045739468-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045742318-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045745038-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045747938-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x751542f9ca50> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045750768-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045770738-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045781458-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045785288-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045793968-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045798228-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045801388-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045804298-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045807248-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045820638-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045823828-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045826788-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045830348-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045833308-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045836378-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045839178-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045842748-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045845658-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045848668-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045851548-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045854628-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045857558-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045862178-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045865098-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045868058-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045880598-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045883927-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045886887-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045890547-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045893527-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045896517-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045899367-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045902337-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045905317-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045908237-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045911267-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045914197-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045925547-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045933227-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045936167-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045939157-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045942057-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045945037-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045947947-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045950847-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045953827-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045957157-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045960047-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045962897-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045969687-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045972737-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045975727-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045978757-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045981697-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045984657-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045988217-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045991137-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045994147-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045996997-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.045999987-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046002897-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046005857-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046014837-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046017807-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046020857-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046023827-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046027517-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046030397-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046033357-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046036407-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046039327-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046042977-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046045837-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046049417-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046052407-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046055326-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046058266-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046061176-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046064106-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046067036-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046069906-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046072886-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046076436-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046079886-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046082846-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046085746-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046088656-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046091566-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046094466-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046097476-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046100406-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046103366-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046106316-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046109166-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046112136-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046115086-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046118226-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046121276-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046124156-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046127116-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046129976-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046132966-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046141116-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046144456-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046147406-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046150386-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046153286-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046156316-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046159206-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046162156-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046165636-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046168656-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046171556-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046174536-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046177366-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046180206-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046186076-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046189406-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046192306-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046195166-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046198056-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046200976-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046204576-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046207466-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046210356-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046213346-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046216316-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046219366-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046222346-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046225366-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046228276-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046231125-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046234015-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046236895-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046239745-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046242685-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046245575-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046248415-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046251275-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046254205-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046257035-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046265155-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046268045-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046270925-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046273825-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046276805-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046279685-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046282595-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046285485-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046288345-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046291245-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046294175-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046297205-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046300055-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046302925-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046305745-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046308585-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046311485-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046314365-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046317275-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046320225-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046323135-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046325985-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046329325-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046332185-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046335125-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046338115-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046340985-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046343965-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046347045-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046349995-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046353335-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046356185-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046359025-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046361865-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046364695-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046367605-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046370445-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046381035-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046384045-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046386935-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046389755-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046392605-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046395535-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046398465-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046401315-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046404204-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046407054-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046409914-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046412814-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046415634-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046418634-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046421494-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046424404-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046427264-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046430084-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046432914-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046435774-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046438644-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046441524-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046444584-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046447414-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046450274-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046453134-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046455944-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046458824-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046461634-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046464524-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046467744-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046470594-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046473474-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046476394-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046479214-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046482004-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046484814-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046487704-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046495704-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046498614-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046501444-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046504304-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046507194-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046510034-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046512854-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046515774-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046518514-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046522214-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046525194-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046528104-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046530954-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046533734-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046536604-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046539564-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046542474-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046545764-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046548664-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046551524-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046554344-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046557244-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046560074-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046562974-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046565864-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046568724-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046571544-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046574374-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046577274-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046580113-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046582993-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046588533-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046591343-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046594273-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x751542f9ca50> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046597233-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046600203-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046603113-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046605943-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046609003-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046616963-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046620003-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046622943-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046626403-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046629343-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046632333-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046635243-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046638183-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046641083-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046644073-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046646813-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046649663-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046652573-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046655473-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046658363-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046661293-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046664613-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046667483-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046670343-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046673193-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046676033-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046678953-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046681843-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046684773-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046688153-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046696263-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046699973-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046702923-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046705763-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046708683-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046711633-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046714613-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046717483-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046720333-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046723173-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046728613-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046731523-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046734413-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046737303-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046740233-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046743123-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046746003-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046748933-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046751843-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046754772-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046757672-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046760562-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046763462-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046766322-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046769242-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046772092-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046774972-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046778422-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046781332-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046784242-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046787122-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046789982-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046792782-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046795612-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046798392-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046801222-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046813812-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046816902-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046819772-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046822792-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046825852-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046828792-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046832252-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046835122-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046837962-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046840892-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046843752-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046846632-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046849852-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046852682-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046855532-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046858412-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046861252-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046864172-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046867002-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046869842-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046872682-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046875492-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046878322-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046881152-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046884032-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046886932-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046891012-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046893882-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046896782-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046899632-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046902542-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046905422-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046908262-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046911192-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046914072-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046928491-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046933561-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046939471-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046942421-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046945341-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046948321-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046951231-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046959761-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046962611-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046965431-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046968291-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046971171-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046974021-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046976981-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046979791-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046982721-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046985671-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046988581-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046991421-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046994261-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.046997091-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047000001-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047002811-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047005641-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047008601-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047011451-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047014301-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047017151-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047020071-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047022971-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047025821-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047028681-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047031551-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047034421-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047037301-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047040141-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047043021-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047045911-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047048721-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047051521-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047054341-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047057191-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047060021-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047062891-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047065761-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047074541-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047077461-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047080301-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047083151-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047086021-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047088861-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047091761-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047094611-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047097511-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047100361-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047103220-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047106120-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047108990-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047111860-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047114900-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047117790-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047120740-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047123610-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047126460-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047129390-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047132290-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047135180-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047138040-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047143690-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047146640-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047149500-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047152350-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047155160-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047158030-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047160940-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047163830-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047166730-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047169610-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047172440-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047175280-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047178130-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047181160-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047188920-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047191780-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047194660-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047197530-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047200410-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047203310-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047206160-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047209080-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047212010-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047214910-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047217780-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047220620-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047223460-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047226340-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047229220-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047232060-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047234940-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047237760-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047240620-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047243530-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047246380-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047249190-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047252010-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047254850-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047257710-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047260560-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047263430-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047266290-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047269130-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047271970-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047274780-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047277629-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047280559-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047283409-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047286269-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047289109-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047291979-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047294839-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047297719-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047300619-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047308149-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047310969-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047314999-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047317929-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047320819-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047323669-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047326419-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047329269-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047332179-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047346269-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047363489-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047366779-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047370659-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047373369-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047377719-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047381869-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047386129-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047390959-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047395179-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047405139-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047408169-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047411109-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047413849-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047419049-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047422109-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047424829-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047427689-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x751542f9ca50> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047430469-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047433329-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047436049-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047438929-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047441839-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047444749-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047447529-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047527848-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047530988-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047534468-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047538298-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047541228-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047544008-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047546878-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047549758-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047552418-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047555208-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047558088-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047561278-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047564008-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047566738-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047569608-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047572358-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047575268-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047578008-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047580758-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047583598-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047586368-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047589188-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047592088-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047594928-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047597628-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047600428-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047603168-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047605928-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047611898-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047614898-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047623088-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047625847-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047628567-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047631467-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047634847-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047637657-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047640387-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047643207-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047645947-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047648727-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047651447-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047654257-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047657007-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047659697-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047662637-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047665497-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047668257-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047671097-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047673847-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047676567-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047679267-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047681997-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047684737-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047687507-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047690217-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047692907-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047695777-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047698507-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047701217-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047703947-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047706697-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047709457-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047712417-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047715177-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047717907-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047725607-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047728387-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047731887-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047734747-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047737587-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047740367-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047743057-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047746937-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047749697-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047752467-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047755227-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047757957-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047760737-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047763527-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047766277-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047768987-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047771717-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047774467-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047777217-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047779937-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047782757-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047785467-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047788207-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047790987-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047793857-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047796617-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047799346-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047805076-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047807986-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047810786-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047813516-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047816316-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047819076-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047821816-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047824786-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047827766-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047830706-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047833446-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047836156-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047840376-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047843186-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047845936-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047853976-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047856776-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047859526-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047862306-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047865016-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047867726-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047870516-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047873186-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047875966-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047878796-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047881506-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047884246-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047887046-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047889776-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047892516-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047895336-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047898106-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047900946-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047904486-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047907296-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047910016-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047912796-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047915536-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047925866-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047933816-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047937966-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047942166-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047946246-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047950186-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047954156-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047958176-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047962386-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047966356-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047970466-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047974535-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047978595-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047982725-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047986585-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.047997535-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048001615-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048005675-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048009785-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048013445-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048016175-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048019355-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048022095-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048024825-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048027535-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048030375-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048033225-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048035965-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048038745-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048041615-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048047795-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048050635-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048053495-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048056335-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048059115-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048062605-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048065405-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048068165-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048070895-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048073935-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048076685-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048079465-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048082205-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048084965-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048087685-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048090465-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048093265-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048096005-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048098725-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048101535-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048104285-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048106995-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048109745-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048117135-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048120745-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048123575-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048126295-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048129085-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048132565-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048135305-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048138025-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048140745-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048143475-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048146295-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048149054-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048151974-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048154694-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048157394-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048160114-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048162904-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048165624-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048168354-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048171084-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048173844-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048176574-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048179324-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048182094-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048185134-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048187884-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048190914-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048193654-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048197834-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048202024-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048205974-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048210054-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048214194-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048218454-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048222224-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048226054-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048234354-05:00 def daily_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048237184-05:00 > return _run("daily") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048239884-05:00 ^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048242484-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048245254-05:00 tests/test_report_traits_live.py:94: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048251734-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048254504-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048257254-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048260014-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048262734-05:00 src/storeminder/runner.py:340: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048265494-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048268184-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048270954-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048273674-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048276384-05:00 src/storeminder/crew.py:463: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048279164-05:00 report_result = _agent.run_daily( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048281854-05:00 src/storeminder/agents/synthesis_agent.py:1023: in run_daily [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048284554-05:00 return self.run(report_type="daily", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048287244-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048289924-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048292724-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048295414-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048298034-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048300834-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x751542f9ca50> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048303594-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048306434-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048309214-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048311994-05:00 baseline = {'sample_count': 15, 'day_of_week': 4, 'total_revenue': 16270.22, 'total_transactions': 590.87, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048314764-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048318164-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...ening | Verify pump access and functionality during 22:00–23:00 | Measure: Fuel gallons in 22:00–23:00 window tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048321584-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,436.97 (+9.5% vs normal Monday)** \nTobacco/Nicotine surged on strong Marlb...iring | Because: Packaged Beverage +3.8% but basket depth lagging | Measure: Avg basket size by daypart (target: 3.6+)' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048326043-05:00 weather = {'yesterday': {'temp_max': 90.1, 'temp_min': 76.8, 'precip_in': 0.0, 'conditions': 'Partly cloudy'}, 'today_forecast':...rtly cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048330183-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...ew staff scheduling: confirm if high-performing employee "Luna" was off-duty during period of decline — Do by 10:00 AM' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048341213-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... by EOD tomorrow \n- Capitalize on Red Bull Original Energy surge with front-end product placement — Do by 2026-07-11' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048345493-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.18 (+2% vs normal Frida...thorization and closeout discipline | Because: Elevated voids and service time | Measure: Reduce voids by 30% tomorrow' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048349823-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... to pre-empt weekend traffic. \n- Monitor Murphy USA and Exxon for further moves; escalate if below $3.400 sustained.' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048354073-05:00 prior_actions = None, report_type = 'daily', weekly_days = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048358263-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048362233-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048366423-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048370623-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048374733-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048378923-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048383253-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048387543-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048391763-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048396453-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048401003-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048405183-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048414903-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048419593-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048423923-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048428093-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048432213-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048436533-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048440673-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048444793-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048448843-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048453013-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048457003-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048460923-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048465683-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048469803-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048473833-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048478103-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048482003-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048485903-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048489893-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048502482-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048507012-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048511202-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048515412-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048519392-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048523552-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048528212-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048532172-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048536562-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048540482-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048544672-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048548802-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048552772-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048556532-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048560182-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048565572-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048569472-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048573122-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048576752-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048580312-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048583982-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048587952-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048592102-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048596462-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048600402-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048604632-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048608802-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048612682-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048616742-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048620662-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048624592-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048628462-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048632252-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048636202-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048647622-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048651982-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048656162-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048660322-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048664442-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048669882-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048674181-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048678541-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048683211-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048687331-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048691621-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048695801-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048700221-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048711211-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048715821-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048720171-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048724251-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048728371-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048732671-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048736891-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048741471-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048745771-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048749971-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048754241-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048758271-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048762401-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048766471-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048770621-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048774711-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048778951-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048783631-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048788061-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048792211-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048796271-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048800291-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048804661-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048809581-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048813451-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048817241-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048821181-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048825631-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048829831-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048841551-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048846080-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048850160-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048854170-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048858260-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048862510-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048866780-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048870970-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048874970-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048880050-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048884450-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048888580-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048892880-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048897220-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048901310-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048905720-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048909980-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048914520-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048925520-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048933720-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048937990-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048942450-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048946550-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048950870-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048955140-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048959760-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048964100-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048968240-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048972400-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048976780-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048981980-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048986440-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048990490-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048995010-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.048999460-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049003520-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049007950-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049012490-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049030269-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049034729-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049038619-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049042589-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049046509-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049050319-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049054479-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049058649-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049062799-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049066769-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049071069-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049075359-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049079229-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049083179-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049087199-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049091079-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049095219-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049099169-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049103249-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049107349-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049111279-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049115409-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049119819-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049123779-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049127939-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049132309-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049136659-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049141229-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049145849-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049150079-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049154579-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049158849-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049163189-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049167699-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049172189-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049177449-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049182019-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049195328-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049199478-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049203888-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049206638-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049209428-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049212148-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049214878-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049217738-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049220488-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049223308-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049226018-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049228808-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049232088-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049234958-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049237768-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049240508-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049243208-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049245958-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049248678-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049251448-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049254148-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049256918-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049259668-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049262378-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049265108-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049267858-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049270588-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049273398-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049288578-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049292608-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049297928-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049301438-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049304628-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049307458-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049310148-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049313208-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049316108-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049318968-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049321848-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049335958-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049338968-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049341848-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049344898-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049347728-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049350568-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049353428-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049356218-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049359378-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049362238-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049365038-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049367868-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049370707-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049374147-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049376907-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049380307-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x75148b044e10> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049383237-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049386407-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049389287-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049392157-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049395067-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049397977-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049401567-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049404417-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049408477-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049411457-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049414327-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049423027-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049425927-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049432157-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049435097-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049438457-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049441327-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049444197-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049447107-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049450047-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049452927-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049455777-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049458597-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049462247-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049465167-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049468057-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049470957-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049474087-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049476947-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049479867-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049482747-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049485617-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049488447-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049491307-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049494197-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049497057-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049499987-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049502907-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049505767-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049508667-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049511537-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049514387-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049517277-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049520117-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049523107-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049525997-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049528867-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049532067-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049539837-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049542677-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049545726-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049548596-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049551436-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049554316-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049557146-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049560096-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049562986-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049565826-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049568646-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049571466-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049574316-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049577136-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049579946-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049582796-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049585626-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049588446-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049591316-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049594146-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049596976-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049599816-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049602916-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049605876-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049608786-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049614376-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049617356-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049620246-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049623196-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049626056-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049628986-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049632016-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049634856-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049637706-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049640586-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049648226-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049651176-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049655006-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049657946-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049660806-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049663706-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049666636-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049669536-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049672426-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049675306-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049678286-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049681256-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049684226-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049687106-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049690196-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049693086-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049696516-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049699446-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049702326-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049705286-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049708126-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049711126-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049714076-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049716956-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049719815-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049722675-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049725595-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049728475-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049731295-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049734135-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049736965-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049739885-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049742725-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049745535-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049748495-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049751385-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049754325-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049757215-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049760075-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049763015-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049765885-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049769375-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049777465-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049780445-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049783345-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049786205-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049789065-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049791895-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049794795-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049797645-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049800555-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049803475-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049807955-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049812395-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049816565-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049821005-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049825465-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049829795-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049834015-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049838555-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049841445-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049844435-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049847355-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049853825-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049856895-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049859915-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049862945-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049865795-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049868685-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049871575-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049875475-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049878415-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049881325-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049884845-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049887735-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049890605-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049893474-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049896324-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049899234-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049908964-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049911934-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049914824-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049929014-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049936554-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049941064-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049945504-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049949724-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049953804-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049957914-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049961824-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049966064-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049970134-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049974104-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049978294-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049982454-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049986534-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049990664-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.049994684-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050000484-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050004494-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050007424-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050010354-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050013204-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050016114-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050018994-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050021954-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050024904-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050027814-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050030654-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050033534-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050036384-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050039214-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050042134-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050044964-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050047854-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050050704-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050059814-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050062754-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050065634-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050068443-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050071303-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050074333-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050077263-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050080173-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050083043-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050085903-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050089033-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050091893-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050098793-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050101763-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050104713-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050107633-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050110463-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050113283-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050116203-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050119033-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050121933-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050124843-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050127743-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050130653-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050133473-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050136383-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050139133-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050142563-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050145493-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050148453-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050151383-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050154153-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050157133-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050160063-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050162903-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050165803-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050168813-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050171713-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050174623-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050183113-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050186003-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050188863-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050191703-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050194563-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050197413-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050200293-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050203153-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050206003-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050208863-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050211733-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050214493-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050217353-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x75148b044e10> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050220253-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050223253-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050226253-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050229203-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050232103-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050235733-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050238683-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050241552-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050247432-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050250472-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050253332-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050256182-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050264062-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050267132-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050270092-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050272982-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050275842-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050278692-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050281552-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050284522-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050287422-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050290312-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050293212-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050296122-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050299142-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050302042-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050304922-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050307872-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050310842-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050313822-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050316662-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050319562-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050322602-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050325472-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050328412-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050331282-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050334182-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050337202-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050340122-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050342962-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050345832-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050348682-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050351662-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050354632-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050357502-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050360362-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050363202-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050366112-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050369082-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050371962-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050380312-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050384242-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050387232-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050390232-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050393212-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050396082-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050399042-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050401892-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050404712-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050407622-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050413142-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050416071-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050418951-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050421881-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050424771-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050427681-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050430641-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050433521-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050436381-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050439271-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050442211-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050445181-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050448221-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050451061-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050453931-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050456791-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050459641-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050462541-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050465361-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050468311-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050471191-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050474061-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050476991-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050479871-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050482741-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050485661-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050493451-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050496481-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050499381-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050502281-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050505191-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050508071-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050511001-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050514651-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050517561-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050520551-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050524241-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050527241-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050530301-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050534321-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050537841-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050540761-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050543721-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050546651-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050549641-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050552541-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050555421-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050558251-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050561101-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050563981-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050566861-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050569791-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050572701-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050575531-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050578381-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050581251-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050584061-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050587051-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050589950-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050592910-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050595870-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050598740-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050601600-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050604550-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050608400-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050611310-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050614200-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050617180-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050625400-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050628380-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050631470-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050637120-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050640130-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050642970-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050646000-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050648990-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050651880-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050654730-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050657590-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050660490-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050663330-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050666170-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050669070-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050671950-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050674850-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050677680-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050680640-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050683540-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050686450-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050689370-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050692270-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050695900-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050698840-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050701710-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050704570-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050707490-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050710310-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050713200-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050716130-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050719020-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050721850-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050724740-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050727620-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050730570-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050733460-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050736320-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050744020-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050747010-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050749870-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050752720-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050755710-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050758570-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050761430-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050764419-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050767309-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050770269-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050773119-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050775939-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050778789-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050781639-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050784479-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050787389-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050790249-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050793109-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050796089-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050798959-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050801809-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050804709-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050807559-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050810749-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050813649-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050816529-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050833389-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050841289-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050845749-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050850519-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050855969-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050860449-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050865259-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050869399-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050873659-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050877699-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050881849-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050895439-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050906409-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050910819-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050914979-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050929739-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050936879-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050941068-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050945228-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050949718-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050954068-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050958218-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050962498-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050966698-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050970578-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050974718-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050978648-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050982638-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050986718-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050990808-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050994828-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.050998808-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051003908-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051007858-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051012698-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051016788-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051021078-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051025158-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051029008-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051033238-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051037298-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051041428-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051045768-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051050098-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051054338-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051058648-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051062898-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051067278-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051071268-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051075968-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051088508-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051092628-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051096728-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051100688-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051105158-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051109117-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051113187-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051117197-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051121547-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x75148b044e10> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051125717-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051130507-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051135037-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051139267-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051144587-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051148837-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051154267-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051163367-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051167767-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051172197-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051176337-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051180627-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051184957-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051189247-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051199917-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051204867-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051208767-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051212847-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051217057-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051221227-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051225417-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051229537-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051233537-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051237907-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051242097-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051246317-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051250537-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051255577-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051259727-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051263747-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051267927-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051272067-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051276156-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051280346-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051284316-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051288366-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051292526-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051296566-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051300586-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051304676-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051308856-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051312786-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051316936-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051320996-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051324976-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051329086-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051333026-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051337136-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051341386-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051345346-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051349626-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051353746-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051357846-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051368546-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051372666-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051376856-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051382066-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051390636-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051395046-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051399336-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051403526-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051407776-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051411826-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051416016-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051420206-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051424116-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051428266-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051432356-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051436446-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051440696-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051447035-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051452195-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051456495-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051460595-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051464765-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051468735-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051472685-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051476965-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051481095-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051485365-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051489545-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051493865-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051497965-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051502195-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051506445-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051511085-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051515145-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051519395-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051524195-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051534375-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051538755-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051542605-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051546465-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051550515-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051554495-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051558875-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051562955-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051569885-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051574145-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051578075-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051583365-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051587405-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051591705-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051595955-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051599795-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051604115-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051609405-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051613594-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051617684-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051621844-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051625744-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051629904-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051633914-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051637764-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051641904-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051645994-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051649824-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051654134-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051658824-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051662994-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051667094-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051671284-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051675354-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051679494-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051683544-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051687644-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051696114-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051700604-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051704724-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051708864-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051712944-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051723684-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051727834-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051732044-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051736214-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051740394-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051744604-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051748554-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051752624-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051756604-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051760784-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051764764-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051769154-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051773344-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051777434-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051781613-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051785613-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051789573-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051793713-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051797823-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051801823-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051805853-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051810103-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051814253-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051818343-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051822243-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051826223-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051830303-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051834443-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051838523-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051842683-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051846853-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051850813-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051854743-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051858963-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051862963-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051867043-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051871043-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051884523-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051888753-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051892703-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051896943-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051901063-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051905223-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051909563-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051913963-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051926113-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051933063-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051937213-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051941433-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051945633-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051949762-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051954982-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051959152-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051963282-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051967652-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051971912-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051980212-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051984392-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051988522-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051993022-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.051997052-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052001132-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052005472-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052009522-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052013722-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052017852-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052024052-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052027972-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052032022-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052036172-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052040342-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052044202-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052048192-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052052252-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052056402-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052070042-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052074412-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052078682-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052082872-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052087742-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052091922-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052097552-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052101922-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052105972-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052110072-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052114252-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052118302-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052122282-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052126751-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052130841-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052134861-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052138971-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052143011-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052146931-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052150791-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052155091-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052159411-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052163661-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052167781-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052171631-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052175651-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052179881-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052183921-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052188021-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052192101-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052196741-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052201031-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052205101-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052209201-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052213441-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052217441-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052221361-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052225391-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052229411-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052240161-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052244321-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052248401-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052252601-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052256371-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052260401-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x75148b044e10> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052264371-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052268461-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052272561-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052281021-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052285581-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052289871-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052294211-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052298300-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052302480-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052306770-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052311000-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052315730-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052319790-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052323990-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052328140-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052339130-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052343090-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052347420-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052351580-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052355560-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052359660-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052363700-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052367880-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052372070-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052376140-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052381560-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052385650-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052389920-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052393850-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052398110-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052402260-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052406490-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052410540-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052414780-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052419120-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052423510-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052427790-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052431820-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052436070-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052440240-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052444410-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052448550-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052452650-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052456670-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052460710-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052464880-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052473129-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052477389-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052481709-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052485889-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052490039-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052494279-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052498549-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052502619-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052506679-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052511499-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052522169-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052526359-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052530469-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052534599-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052538809-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052542889-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052546959-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052550919-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052555089-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052559339-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052563489-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052567519-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052571589-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052575509-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052579649-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052583769-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052587899-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052591879-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052596259-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052600449-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052604519-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052608589-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052612589-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052616639-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052620969-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052625019-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052629109-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052633309-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052637439-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052641459-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052645549-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052649458-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052653838-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052657868-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052662488-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052666568-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052670858-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052681668-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052685898-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052690128-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052694418-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052699028-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052703228-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052707378-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052711318-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052715318-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052720268-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052724368-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052729038-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052733278-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052737518-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052741578-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052745758-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052750428-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052758548-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052762788-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052767178-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052771368-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052775458-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052779638-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052783588-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052787828-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052792168-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052796288-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052800398-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052804428-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052808458-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052812488-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052816758-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052820678-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052824987-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052829117-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052833227-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052838057-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052842047-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052846067-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052850207-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052854437-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052865087-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052869407-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052873527-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052877747-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052881857-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052886747-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052890957-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052895067-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052899207-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052903487-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052908407-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052912677-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052916817-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052928617-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052932997-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052937237-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052941287-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052945537-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052949647-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052953827-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052957907-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052961927-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052965887-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052969937-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052974137-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052978247-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052982287-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052986377-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052990487-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052994477-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.052998466-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053002656-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053006886-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053011146-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053015346-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053019456-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053023546-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053034376-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053038436-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053042386-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053057096-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053061436-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053064336-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053067046-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053069756-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053072486-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053078876-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053081716-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053084526-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053087596-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053091876-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053094736-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053097496-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053100326-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053103096-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053105916-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053108646-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053111456-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053114806-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053117736-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053120486-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053123256-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053125996-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053128816-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053131546-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053134306-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053137026-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053139816-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053142536-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053145996-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053148776-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053151556-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053154276-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053157036-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053159756-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053171905-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053174765-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053177485-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053180195-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053183055-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053185755-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053188495-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053191225-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053194005-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053196715-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053199425-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053202155-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053205085-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053207795-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053210485-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053213185-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053215845-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053218835-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError@pytest.fixture(scope="module") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053221635-05:00 def weekly_report(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053224445-05:00 > return _run("weekly") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053227225-05:00 ^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053229815-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053232525-05:00 tests/test_report_traits_live.py:99: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053235275-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053237975-05:00 tests/test_report_traits_live.py:75: in _run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053240715-05:00 res = fn(store, end_date=d, dry_run=True, deliver=False, clean=True) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053243455-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053246245-05:00 src/storeminder/runner.py:359: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053249005-05:00 return _run_report(params, clean=clean) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053251745-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053254445-05:00 src/storeminder/runner.py:193: in _run_report [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053257175-05:00 result = run_pipeline( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053259915-05:00 src/storeminder/crew.py:456: in run_pipeline [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053262755-05:00 report_result = _agent.run_weekly( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053265525-05:00 src/storeminder/agents/synthesis_agent.py:1028: in run_weekly [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053268235-05:00 return self.run(report_type="weekly", **kwargs) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053271065-05:00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053273775-05:00 src/storeminder/agents/synthesis_agent.py:1073: in run [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053276445-05:00 user = self._build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053284075-05:00 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053286795-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053292695-05:00 self = <storeminder.agents.synthesis_agent.SynthesisAgent object at 0x75148b044e10> [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053295555-05:00 report_date = datetime.date(2026, 7, 10), store_id = 'Fastime' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053298435-05:00 trans = {'total_transactions': 618, 'open_hour_start': 4, 'open_hour_end': 21, 'report_date_filter': '2026-07-10', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053301275-05:00 scan = {'total_scan_rows': 1940, 'report_date_filter': '2026-07-10', 'total_sales': 6436.97, 'avg_item_price': 3.88, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053304085-05:00 baseline = {'day_of_week': 21, 'total_revenue': 100081.6, 'total_transactions': 3568.94, 'fuel_gallons': 16961.39, ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053307785-05:00 flags = [{'metric': 'rank_drop', 'label': 'Rank Drop: COPENHAGEN FINE CUT', 'today': 40, 'baseline': 13, ...}, {'metric': 'ran...': 29, ...}, {'metric': 'rank_drop', 'label': 'Rank Drop: BUD LIGHT BEER 12 O', 'today': 33, 'baseline': 22, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053310575-05:00 fuel_section = '## 2. Fuel \n**2,583 gal | $9,446 | 279 fuel transactions** \nFuel volume came in at 2,583 gallons, down from 2,758...rnoon shift | Run fuel-to-inside conversion play at the pump and register | Measure: Inside sales per 100 fuel gallons' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053313655-05:00 inside_section = '## 3. Inside Sales\n\n**Inside Sales: $6,437 (+9.5% vs normal Monday)** \nTobacco / Nicotine surged, led by Marlboro...URO ORIGINAL TOR stock | Because: Zero sales on $1.2k+ baseline cigars 🔴 | Measure: Confirm receipt or reorder by noon' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053316535-05:00 weather = {'yesterday': {'temp_max': 88.3, 'temp_min': 75.4, 'precip_in': 0.0, 'conditions': 'Clear'}, 'today_forecast': {'temp_...cloudy'}, 'rain_hours_today': [], 'weather_impact_assessment': 'Low — weather was mild, not a significant factor', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053319305-05:00 external_section = '## External Context\n\n**Google Reviews (5 reviews)** \nAverage rating of recent reviews (3.0/5) is below overall st...\n- Review staff scheduling to assess if low-performance shifts align with negative reviews and sales dips — Do by EOD' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053322145-05:00 loyalty_section = '## Loyalty & Promotions\n\n**Redemption Summary**\n| Promotion | Item | Today | Period Avg | Delta | Status |\n|-----... Share success of Red Bull Original and Summer Editions with marketing for potential campaign expansion — Do by Monday' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053325405-05:00 ops_section = '## 5. Operations\n\n**Transactions & Throughput** \n962 total transactions | Avg ticket: $17.10 (+12% vs normal Frid...tional hours recommended. Optimization reallocates existing ownership to high-impact windows, especially Friday peak.*' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053328125-05:00 fuel_pricing_section = '## Fuel Pricing\n\n**Current Market** \n| Station | Regular | Midgrade | Premium | Diesel | Distance | \n|---------... \n- Reduce Regular to $3.549 by 5:00 PM today \n- Monitor Murphy USA and FASTIME for price updates in next 24 hours' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053330855-05:00 prior_actions = None, report_type = 'weekly' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053333595-05:00 weekly_days = [{'date': '2026-07-04', 'dow_name': 'Saturday', 'total_revenue': 7392.12, 'fuel_gallons': 1142.1, ...}, {'date': '2026...42.4, ...}, {'date': '2026-07-09', 'dow_name': 'Thursday', 'total_revenue': 16227.6, 'fuel_gallons': 2780.6, ...}, ...] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053336325-05:00 dow_profile = None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053339095-05:00 kwargs = {'category_baselines': None, 'schedule_section': None, 'weekly_category_totals': None, 'ext_fetch_date': '2026-07-12', ...} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053341745-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053344535-05:00 def _build_user_prompt( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053351654-05:00 self, report_date, store_id, trans, scan, baseline, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053354404-05:00 flags, fuel_section, inside_section, weather, external_section, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053357184-05:00 loyalty_section, ops_section, fuel_pricing_section, prior_actions, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053359874-05:00 report_type: str = "daily", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053362604-05:00 weekly_days: Optional[List[Dict]] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053365304-05:00 dow_profile: Optional[Dict] = None, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053368024-05:00 **kwargs, [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053370734-05:00 ) -> str: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053373484-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053376254-05:00 # ── KPI table ───────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053379014-05:00 kpi_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053381864-05:00 "| Metric | Today | Baseline | Delta | Priority |", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053384674-05:00 "|--------|-------|----------|-------|----------|", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053387404-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053390114-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053393604-05:00 # Keys that live in scan_summary (inside sales) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053396364-05:00 _scan_keys = {'total_sales', 'avg_item_price', 'total_scan_rows'} [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053399134-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053401904-05:00 def kpi_row(label, key, fmt_str=",.0f", prefix="", priority=None): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053404674-05:00 # Prefer scan for inside-sales metrics, trans for everything else [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053410034-05:00 if key in _scan_keys: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053412794-05:00 t = scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053415554-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053418324-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053421134-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053423854-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053426554-05:00 return [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053429274-05:00 t_str = f"{prefix}{t:{fmt_str}}" if isinstance(t, (int, float)) else str(t) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053432034-05:00 b_str = f"{prefix}{b:{fmt_str}}" if isinstance(b, (int, float)) else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053434764-05:00 delta = f"{((t-b)/b*100):+.1f}%" if isinstance(t,(int,float)) and isinstance(b,(int,float)) and b else "—" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053437664-05:00 # Priority: use flag severity if exists, else spec default [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053440424-05:00 flag = next((f for f in flags if f['metric'] == key), None) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053443154-05:00 pri = flag['severity'] if flag else (priority or "—") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053445844-05:00 kpi_lines.append(f"| {label} | {t_str} | {b_str} | {delta} | {pri} |") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053448574-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053451334-05:00 kpi_row("Total Transactions", "total_transactions", ",.0f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053454154-05:00 kpi_row("Total Sales", "total_revenue", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053456894-05:00 kpi_row("Inside Sales", "total_sales", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053459654-05:00 kpi_row("Avg Inside Ticket", "avg_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053462404-05:00 kpi_row("Avg Fuel Ticket", "avg_fuel_ticket", ",.2f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053469484-05:00 kpi_row("Fuel Gallons", "fuel_gallons", ",.1f", "", "HIGH") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053472314-05:00 kpi_row("Fuel Sales $", "fuel_sales", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053474994-05:00 kpi_row("Fuel Transactions", "fuel_transactions", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053478444-05:00 kpi_row("Avg Gallons/Tx", "avg_gallons_per_tx", ",.2f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053481414-05:00 kpi_row("Forecourt Conv %", "forecourt_conversion_pct", ",.1f", "", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053484164-05:00 kpi_row("Void Count", "void_count", ",.0f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053486964-05:00 kpi_row("Void Total $", "void_total_amt", ",.2f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053491144-05:00 kpi_row("Inside/100 Gal (weekly avg)", "inside_per_100_gal", ",.0f", "$", "MEDIUM") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053494174-05:00 kpi_row("Eff. Fuel Price", "effective_fuel_price", ",.3f", "$", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053496914-05:00 kpi_row("Inside Share %", "inside_sales_share_pct", ",.1f", "", "LOW") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053499654-05:00 kpi_summary = "\n".join(kpi_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053502364-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053505304-05:00 # ── Derived metrics for snapshot header ──────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053508104-05:00 def _dm(key, label, prefix="", suffix="", decimals=2): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053511024-05:00 t = trans.get(key) if trans.get(key) is not None else scan.get(key) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053513774-05:00 b = baseline.get(key) if baseline else None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053516524-05:00 if t is None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053519253-05:00 return None [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053521973-05:00 t_str = f"{prefix}{float(t):,.{decimals}f}{suffix}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053524703-05:00 if b and float(b) > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053527423-05:00 pct = (float(t) - float(b)) / float(b) * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053530213-05:00 return f"{label}: {t_str} ({pct:+.1f}% vs baseline)" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053532983-05:00 return f"{label}: {t_str}" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053535703-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053538453-05:00 dm_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053541223-05:00 v = _dm('inside_per_100_gal', 'Inside/100gal', '$', '', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053543973-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053546733-05:00 v = _dm('effective_fuel_price', 'Effective fuel price', '$', '/gal', 3) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053549463-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053552183-05:00 v = _dm('inside_sales_share_pct','Inside share of sales', '', '%', 1) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053554943-05:00 if v: dm_lines.append(v) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053557633-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053560393-05:00 gap = trans.get('fuel_inside_gap_pct') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053563143-05:00 if gap is not None: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053565943-05:00 direction = "FUEL OUTPACING INSIDE" if gap > 0 else "INSIDE OUTPACING FUEL" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053568813-05:00 dm_lines.append(f"Fuel-vs-Inside gap: {gap:+.1f}pp ({direction})") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053571543-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053574263-05:00 derived_metrics = "\n".join(dm_lines) if dm_lines else "N/A" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053582273-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053585143-05:00 # ── Flags summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053587883-05:00 if flags: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053590603-05:00 flags_str = "\n".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053593323-05:00 f"- [{f['severity']}] {f['label']}: {f['note']}" for f in flags) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053596023-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053598723-05:00 flags_str = "No significant anomalies detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053601463-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053606933-05:00 # ── Shift summary ───────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053609753-05:00 shifts = trans.get('shift_summary', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053612593-05:00 if shifts: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053615343-05:00 shift_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053618273-05:00 for name, data in shifts.items(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053621043-05:00 rev = data.get('revenue', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053623763-05:00 tx = data.get('transactions', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053626563-05:00 gals = data.get('fuel_gallons', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053629513-05:00 shift_lines.append(f"- {name}: ${rev:,.2f} inside | {tx} tx | {gals:,.1f} gal fuel") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053632263-05:00 shift_summary = "\n".join(shift_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053635033-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053637703-05:00 shift_summary = "Shift data not available." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053640413-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053643243-05:00 # ── Gap / zero-tx hours ─────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053646023-05:00 gaps = trans.get('top_hourly_gaps', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053648853-05:00 zero_tx = trans.get('zero_tx_hours', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053651583-05:00 gap_lines = [] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053654293-05:00 if gaps: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053657003-05:00 gap_str = ", ".join( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053659783-05:00 "{:02d}:00 ({} tx)".format(g['_hour'], g['tx_count']) for g in gaps) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053662553-05:00 gap_lines.append(f"Top gap hours: {gap_str}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053666113-05:00 if zero_tx: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053668873-05:00 gap_lines.append(f"Zero-tx hours (open window): {zero_tx}") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053672483-05:00 gap_summary = "\n".join(gap_lines) if gap_lines else "No unusual gaps detected." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053675203-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053677993-05:00 # Authoritative store hours (issue #128): when Google Places supplies the [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053680693-05:00 # store's real hours, prepend them and instruct the model to treat [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053683483-05:00 # off-hours zero activity as expected closure rather than hedging. The [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053686163-05:00 # gap/zero-tx figures above are already computed against this same window. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053689433-05:00 store_hours_val = kwargs.get('store_hours') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053692253-05:00 if store_hours_val and store_hours_val.get('weekday_text'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053695042-05:00 hrs_lines = ["AUTHORITATIVE STORE HOURS (Google Places — treat as ground truth):"] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053702242-05:00 hrs_lines += [f" {ln}" for ln in store_hours_val['weekday_text']] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053705072-05:00 if store_hours_val.get('open_24h'): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053707762-05:00 hrs_lines.append(" This store operates 24 hours on at least one day.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053710492-05:00 hrs_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053713342-05:00 "Zero-transaction hours OUTSIDE these posted hours are EXPECTED " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053716032-05:00 "CLOSURE — do NOT flag them as gaps and do NOT hedge about whether " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053718722-05:00 "the store was open. Treat zero/low activity DURING posted open " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053721482-05:00 "hours as a real gap worth investigating.") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053724222-05:00 gap_summary = "\n".join(hrs_lines) + "\n\n" + gap_summary [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053726942-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053729692-05:00 # ── Weather ─────────────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053732462-05:00 if weather: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053735232-05:00 temp = weather.get('temp', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053738022-05:00 precip = weather.get('precipitation_in', 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053740762-05:00 conds = list(weather.get('conditions', {}).keys()) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053743512-05:00 impact = weather.get('weather_impact_assessment', '') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053746272-05:00 yd = weather.get('yesterday', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053749102-05:00 td = weather.get('today_forecast', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053751832-05:00 rain_hrs= weather.get('rain_hours_today', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053754622-05:00 weather_str = ( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053757352-05:00 f"Report day: {yd.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053760102-05:00 f"{yd.get('temp_min','?')}–{yd.get('temp_max','?')}°F | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053763302-05:00 f"{yd.get('precip_in',0)}\" precip\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053766092-05:00 f"Today forecast: {td.get('conditions','N/A')} | " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053768822-05:00 f"{td.get('temp_min','?')}–{td.get('temp_max','?')}°F\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053771562-05:00 f"Impact assessment: {impact}\n" [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053774282-05:00 + (f"Rain hours: {rain_hrs}\n" if rain_hrs else "") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053777072-05:00 ) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053779782-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053782502-05:00 weather_str = "No weather data provided." [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053785302-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053788102-05:00 # ── Schedule section ────────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053790842-05:00 schedule_section = kwargs.get('schedule_section', None) or '' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053793582-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053800932-05:00 # ── Category baselines ──────────────────────────────────────────────── [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053803772-05:00 cat_baselines = kwargs.get('category_baselines', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053806622-05:00 # weekly_category_totals: actual accumulated weekly revenue per category [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053813962-05:00 # passed from Cell 39 _week_cat — USE THESE VERBATIM in the report table [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053816792-05:00 weekly_cat_totals = kwargs.get('weekly_category_totals', {}) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053819482-05:00 _is_weekly = (report_type == 'weekly') [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053822262-05:00 # Authoritative per-category revenue comes from the owner-mapped [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053825062-05:00 # category_mix (preprocessor). Post-mapping it is aggregated by taxonomy [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053827762-05:00 # name and already reconciles to inside sales, so it — NOT the seeded [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053830622-05:00 # baselines — must drive the category table. Previously this block only [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053833472-05:00 # emitted categories that had a seeded history baseline; when baselines [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053836302-05:00 # were sparse or unseeded the model received no authoritative totals and [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053839192-05:00 # dumped the bulk of inside sales into "Other / unclassified" (issue #81). [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053841992-05:00 _cat_mix_rows = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053844832-05:00 c for c in scan.get('category_mix', []) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053847652-05:00 if isinstance(c.get('category'), str) and str(c.get('category')).strip() [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053850362-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053853102-05:00 _period_lbl = 'This Week' if _is_weekly else 'Today' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053855822-05:00 if _is_weekly and weekly_cat_totals: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053858532-05:00 # Legacy notebook path passes pre-accumulated weekly totals verbatim. [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053861362-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053864072-05:00 "WEEKLY Category Totals — USE THESE EXACT NUMBERS in Section 3 table.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053866932-05:00 "DO NOT invent or estimate different values. These are computed from actual data.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053869791-05:00 f" {'Category':<30} {'This Week':>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053872511-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053875211-05:00 for cat, week_rev in sorted(weekly_cat_totals.items(), [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053878041-05:00 key=lambda x: -x[1]): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053880771-05:00 if not isinstance(cat, str) or not cat.strip(): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053883541-05:00 continue [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053886291-05:00 avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053889091-05:00 if avg > 0: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053891821-05:00 pct = (week_rev - avg) / avg * 100 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053894531-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053897251-05:00 f" {cat:<30} ${week_rev:>10,.0f} ${avg:>10,.0f}/day {pct:>+7.1f}%") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053899991-05:00 else: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053902731-05:00 _cb_lines.append( [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053905501-05:00 f" {cat:<30} ${week_rev:>10,.0f} (no baseline)") [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053908201-05:00 category_baselines_str = "\n".join(_cb_lines) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053910931-05:00 elif _cat_mix_rows: [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053913651-05:00 _classified = sum((c.get('revenue') or 0) for c in _cat_mix_rows) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053916381-05:00 _cb_lines = [ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053935761-05:00 f"Per-category inside revenue ({_period_lbl}) — USE THESE EXACT NUMBERS " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053946871-05:00 f"in the Section 3 category table. They are computed from the owner's " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053950681-05:00 f"merchandise-code taxonomy and already sum to inside sales " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053954521-05:00 f"(${_classified:,.0f}). Only the row explicitly labelled " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053958211-05:00 f"'Other / Unclassified' is unclassified — do NOT move any other " [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053962121-05:00 f"category's revenue into 'Other', and do NOT invent different values.", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053966041-05:00 f" {'Category':<30} {_period_lbl:>12} {'Normal/day':>12} {'Delta':>8}", [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053970191-05:00 ] [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053974281-05:00 for c in sorted(_cat_mix_rows, key=lambda x: -(x.get('revenue') or 0)): [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053978111-05:00 cat = str(c['category']) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053981991-05:00 rev = c.get('revenue') or 0 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053985971-05:00 > avg = cat_baselines.get(cat, 0) [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053989851-05:00 ^^^^^^^^^^^^^^^^^ [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053993601-05:00 E AttributeError: 'NoneType' object has no attribute 'get' [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.053997221-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.054001201-05:00 src/storeminder/agents/synthesis_agent.py:1426: AttributeError===JUNIT_END=== [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.054005151-05:00 ----- end live Job logs ----- [pod/bootstrap-pr-report-check-pr244-jvhqk-live-build-pod/step-run-live] 2026-07-12T18:13:19.086842281-05:00 ==> live build: status=Failed conclusion=failure ===== bootstrap-pr-report-check-pr244-jvhqk-post-check-live-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-live-pod/prepare] 2026-07-12T18:13:23.765751481-05:00 2026/07/12 23:13:23 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-live-pod/place-scripts] 2026-07-12T18:13:26.246776193-05:00 2026/07/12 23:13:26 Decoded script /tekton/scripts/script-0-pntph [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-live-pod/step-post-check] 2026-07-12T18:13:30.201318895-05:00 Installing PyJWT + cryptography + requests… ===== bootstrap-pr-report-check-pr244-jvhqk-post-check-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-pod/prepare] 2026-07-12T18:13:21.872442989-05:00 2026/07/12 23:13:21 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-pod/place-scripts] 2026-07-12T18:13:23.431985395-05:00 2026/07/12 23:13:23 Decoded script /tekton/scripts/script-0-866dl [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-pod/step-post-check] 2026-07-12T18:13:26.286526484-05:00 Installing PyJWT + cryptography + requests… ===== bootstrap-pr-report-check-pr244-jvhqk-post-check-traits-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-traits-pod/prepare] 2026-07-12T18:13:22.060321265-05:00 2026/07/12 23:13:22 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-traits-pod/place-scripts] 2026-07-12T18:13:23.478741326-05:00 2026/07/12 23:13:23 Decoded script /tekton/scripts/script-0-sgs9b [pod/bootstrap-pr-report-check-pr244-jvhqk-post-check-traits-pod/step-post-check] 2026-07-12T18:13:26.270653925-05:00 Installing PyJWT + cryptography + requests… ===== bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/prepare] 2026-07-12T18:13:23.516990405-05:00 2026/07/12 23:13:23 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/place-scripts] 2026-07-12T18:13:24.243746334-05:00 2026/07/12 23:13:24 Decoded script /tekton/scripts/script-0-84np6 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.063137472-05:00 Posting commit status to GitHub [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.063180602-05:00 Repo: storeminder-ai/bootstrap [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.063185942-05:00 SHA: 0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.063188482-05:00 State: failure (Failed) [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.063191222-05:00 Target URL: https://github.com/storeminder-ai/bootstrap/pull/244 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469072071-05:00 { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469091431-05:00 "url": "https://api.github.com/repos/storeminder-ai/bootstrap/statuses/0ebffd844c6fbc14b56725038bc0c1f1a707c0e9", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469097671-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469101471-05:00 "id": 50348364713, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469105041-05:00 "node_id": "SC_kwDOSuVe4s8AAAALuP8TqQ", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469108881-05:00 "state": "failure", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469112651-05:00 "description": "Checks failed", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469115981-05:00 "target_url": "https://github.com/storeminder-ai/bootstrap/pull/244", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469119231-05:00 "context": "tekton/report-build-live", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469122521-05:00 "created_at": "2026-07-12T23:13:30Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469125821-05:00 "updated_at": "2026-07-12T23:13:30Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469129131-05:00 "creator": { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469132861-05:00 "login": "steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469136401-05:00 "id": 702924, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469139831-05:00 "node_id": "MDQ6VXNlcjcwMjkyNA==", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469143881-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469147471-05:00 "gravatar_id": "", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469151871-05:00 "url": "https://api.github.com/users/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469155230-05:00 "html_url": "https://github.com/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469158590-05:00 "followers_url": "https://api.github.com/users/steveblackmon/followers", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469163060-05:00 "following_url": "https://api.github.com/users/steveblackmon/following{/other_user}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469166540-05:00 "gists_url": "https://api.github.com/users/steveblackmon/gists{/gist_id}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469170440-05:00 "starred_url": "https://api.github.com/users/steveblackmon/starred{/owner}{/repo}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469173770-05:00 "subscriptions_url": "https://api.github.com/users/steveblackmon/subscriptions", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469177210-05:00 "organizations_url": "https://api.github.com/users/steveblackmon/orgs", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469181470-05:00 "repos_url": "https://api.github.com/users/steveblackmon/repos", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469186680-05:00 "events_url": "https://api.github.com/users/steveblackmon/events{/privacy}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469190610-05:00 "received_events_url": "https://api.github.com/users/steveblackmon/received_events", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469193870-05:00 "type": "User", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469197290-05:00 "user_view_type": "public", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469200560-05:00 "site_admin": false [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469205350-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.469209520-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.472670510-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-live-pod/step-post-status] 2026-07-12T18:13:30.472683770-05:00 Status posted successfully ===== bootstrap-pr-report-check-pr244-jvhqk-post-status-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/prepare] 2026-07-12T18:13:21.617736597-05:00 2026/07/12 23:13:21 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/place-scripts] 2026-07-12T18:13:23.324266077-05:00 2026/07/12 23:13:23 Decoded script /tekton/scripts/script-0-6gbf7 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.292961124-05:00 Posting commit status to GitHub [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.293003004-05:00 Repo: storeminder-ai/bootstrap [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.293008714-05:00 SHA: 0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.293011744-05:00 State: success (Succeeded) [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.293014624-05:00 Target URL: https://ci-logs.storeminder.ai/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/logs.txt [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720000911-05:00 { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720029331-05:00 "url": "https://api.github.com/repos/storeminder-ai/bootstrap/statuses/0ebffd844c6fbc14b56725038bc0c1f1a707c0e9", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720034821-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720038871-05:00 "id": 50348364475, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720042641-05:00 "node_id": "SC_kwDOSuVe4s8AAAALuP8Suw", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720045931-05:00 "state": "success", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720049321-05:00 "description": "Checks passed", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720052651-05:00 "target_url": "https://ci-logs.storeminder.ai/storeminder-ai/bootstrap/pr-244/bootstrap-pr-report-check-pr244-jvhqk/logs.txt", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720060471-05:00 "context": "tekton/report-build", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720065671-05:00 "created_at": "2026-07-12T23:13:29Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720071951-05:00 "updated_at": "2026-07-12T23:13:29Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720076051-05:00 "creator": { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720080111-05:00 "login": "steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720083411-05:00 "id": 702924, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720086741-05:00 "node_id": "MDQ6VXNlcjcwMjkyNA==", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720090091-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720093421-05:00 "gravatar_id": "", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720097711-05:00 "url": "https://api.github.com/users/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720100981-05:00 "html_url": "https://github.com/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720104911-05:00 "followers_url": "https://api.github.com/users/steveblackmon/followers", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720109181-05:00 "following_url": "https://api.github.com/users/steveblackmon/following{/other_user}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720113061-05:00 "gists_url": "https://api.github.com/users/steveblackmon/gists{/gist_id}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720116401-05:00 "starred_url": "https://api.github.com/users/steveblackmon/starred{/owner}{/repo}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720127681-05:00 "subscriptions_url": "https://api.github.com/users/steveblackmon/subscriptions", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720131431-05:00 "organizations_url": "https://api.github.com/users/steveblackmon/orgs", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720134741-05:00 "repos_url": "https://api.github.com/users/steveblackmon/repos", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720138061-05:00 "events_url": "https://api.github.com/users/steveblackmon/events{/privacy}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720141331-05:00 "received_events_url": "https://api.github.com/users/steveblackmon/received_events", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720144541-05:00 "type": "User", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720149131-05:00 "user_view_type": "public", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720152461-05:00 "site_admin": false [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720155731-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.720158961-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.723963009-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-pod/step-post-status] 2026-07-12T18:13:29.724024648-05:00 Status posted successfully ===== bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/place-scripts] 2026-07-12T18:13:23.437296585-05:00 2026/07/12 23:13:23 Decoded script /tekton/scripts/script-0-c498j [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.290335460-05:00 Posting commit status to GitHub [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.290395529-05:00 Repo: storeminder-ai/bootstrap [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.290400609-05:00 SHA: 0ebffd844c6fbc14b56725038bc0c1f1a707c0e9 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.290403899-05:00 State: success (Succeeded) [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.290407419-05:00 Target URL: https://github.com/storeminder-ai/bootstrap/pull/244 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736632236-05:00 { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736656725-05:00 "url": "https://api.github.com/repos/storeminder-ai/bootstrap/statuses/0ebffd844c6fbc14b56725038bc0c1f1a707c0e9", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736664915-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736669715-05:00 "id": 50348364487, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736674175-05:00 "node_id": "SC_kwDOSuVe4s8AAAALuP8Sxw", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736678425-05:00 "state": "success", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736682575-05:00 "description": "Checks passed", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736687545-05:00 "target_url": "https://github.com/storeminder-ai/bootstrap/pull/244", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736692265-05:00 "context": "tekton/report-traits", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736696485-05:00 "created_at": "2026-07-12T23:13:29Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736700705-05:00 "updated_at": "2026-07-12T23:13:29Z", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736704845-05:00 "creator": { [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736709165-05:00 "login": "steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736713265-05:00 "id": 702924, [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736717465-05:00 "node_id": "MDQ6VXNlcjcwMjkyNA==", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736721545-05:00 "avatar_url": "https://avatars.githubusercontent.com/u/702924?v=4", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736726355-05:00 "gravatar_id": "", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736730815-05:00 "url": "https://api.github.com/users/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736734865-05:00 "html_url": "https://github.com/steveblackmon", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736739035-05:00 "followers_url": "https://api.github.com/users/steveblackmon/followers", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736743495-05:00 "following_url": "https://api.github.com/users/steveblackmon/following{/other_user}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736747635-05:00 "gists_url": "https://api.github.com/users/steveblackmon/gists{/gist_id}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736751725-05:00 "starred_url": "https://api.github.com/users/steveblackmon/starred{/owner}{/repo}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736755775-05:00 "subscriptions_url": "https://api.github.com/users/steveblackmon/subscriptions", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736759935-05:00 "organizations_url": "https://api.github.com/users/steveblackmon/orgs", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736764125-05:00 "repos_url": "https://api.github.com/users/steveblackmon/repos", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736768225-05:00 "events_url": "https://api.github.com/users/steveblackmon/events{/privacy}", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736772275-05:00 "received_events_url": "https://api.github.com/users/steveblackmon/received_events", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736776345-05:00 "type": "User", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736781685-05:00 "user_view_type": "public", [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736787645-05:00 "site_admin": false [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736793115-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.736799045-05:00 } [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.740245075-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/step-post-status] 2026-07-12T18:13:29.740260544-05:00 Status posted successfully [pod/bootstrap-pr-report-check-pr244-jvhqk-post-status-traits-pod/prepare] 2026-07-12T18:13:22.188691235-05:00 2026/07/12 23:13:22 Entrypoint initialization ===== bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/place-scripts] 2026-07-12T18:13:28.519981013-05:00 2026/07/12 23:13:28 Decoded script /tekton/scripts/script-0-9qjp5 [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/step-delete-run-pvcs] 2026-07-12T18:13:31.910821155-05:00 ==> reclaiming workspace PVC(s) owned by PipelineRun=bootstrap-pr-report-check-pr244-jvhqk in ns=tekton-pipelines [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/step-delete-run-pvcs] 2026-07-12T18:13:32.088680079-05:00 ==> deleting PVC pvc-5305e1d69a (5Gi) [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/step-delete-run-pvcs] 2026-07-12T18:13:32.165681995-05:00 persistentvolumeclaim "pvc-5305e1d69a" deleted [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/step-delete-run-pvcs] 2026-07-12T18:13:32.169676562-05:00 ==> requested deletion of 1 run-owned PVC(s) [pod/bootstrap-pr-report-check-pr244-jvhqk-reclaim-workspace-pod/prepare] 2026-07-12T18:13:28.052429829-05:00 2026/07/12 23:13:28 Entrypoint initialization ===== bootstrap-pr-report-check-pr244-jvhqk-sendable-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/prepare] 2026-07-12T18:09:52.405458388-05:00 2026/07/12 23:09:52 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/place-scripts] 2026-07-12T18:09:53.133378307-05:00 2026/07/12 23:09:53 Decoded script /tekton/scripts/script-0-z79vp [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:09:58.369868015-05:00 Installing pytest… [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:04.995231286-05:00 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning. [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:05.103183707-05:00 Neutralizing eager agent imports in src/storeminder/agents/__init__.py (hermetic checkout)… [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:05.104789548-05:00 Running report sendability guard: tests/test_report_validator_cadence.py [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050455306-05:00 ============================= test session starts ============================== [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050564906-05:00 platform linux -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0 -- /usr/local/bin/python [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050570456-05:00 cachedir: .pytest_cache [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050574386-05:00 rootdir: /workspace/source/source [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050578206-05:00 configfile: pyproject.toml [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.050582006-05:00 plugins: cov-7.1.0 [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.101813022-05:00 collecting ... collected 6 items [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.101912801-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.116050620-05:00 tests/test_report_validator_cadence.py::test_leaky_daily_is_not_sendable PASSED [ 16%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.117867540-05:00 tests/test_report_validator_cadence.py::test_clean_daily_passes_without_false_positives PASSED [ 33%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.119182932-05:00 tests/test_report_validator_cadence.py::test_four_week_benchmark_phrasing_is_allowed PASSED [ 50%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.120701473-05:00 tests/test_report_validator_cadence.py::test_weekly_report_is_not_guarded PASSED [ 66%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.121874607-05:00 tests/test_report_validator_cadence.py::test_dow_mismatch_in_headline PASSED [ 83%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743219964-05:00 tests/test_report_validator_cadence.py::test_json_path_guard_scans_narrative_values_only PASSED [100%] [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743313644-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743320234-05:00 ------ generated xml file: /workspace/source/artifacts/junit-sendable.xml ------ [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743324234-05:00 ================================ tests coverage ================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743328624-05:00 _______________ coverage: platform linux, python 3.13.14-final-0 _______________ [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743332144-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743335794-05:00 Coverage XML written to file /workspace/source/artifacts/coverage-sendable.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-sendable-pod/step-pytest] 2026-07-12T18:10:06.743339524-05:00 ============================== 6 passed in 0.58s =============================== ===== bootstrap-pr-report-check-pr244-jvhqk-traits-pod.log ===== [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/prepare] 2026-07-12T18:09:54.216610959-05:00 2026/07/12 23:09:54 Entrypoint initialization [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/place-scripts] 2026-07-12T18:09:55.330066748-05:00 2026/07/12 23:09:55 Decoded script /tekton/scripts/script-0-gz6gp [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:10.441726738-05:00 Installing pytest… [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:13.889122748-05:00 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.103849927-05:00 Running deterministic report-trait catalog: tests/test_report_traits.py [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731739426-05:00 ============================= test session starts ============================== [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731832245-05:00 platform linux -- Python 3.11.15, pytest-9.1.1, pluggy-1.6.0 -- /usr/local/bin/python [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731840245-05:00 cachedir: .pytest_cache [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731844995-05:00 rootdir: /workspace/source/source [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731849965-05:00 configfile: pyproject.toml [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.731854675-05:00 plugins: cov-7.1.0, anyio-4.14.2 [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.979076147-05:00 collecting ... collected 25 items [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.979179127-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.993283176-05:00 tests/test_report_traits.py::test_pennycheck_inside_kpi_matches_journal PASSED [ 4%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.994472119-05:00 tests/test_report_traits.py::test_pennycheck_total_sales_cross_foots_fuel_plus_inside PASSED [ 8%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.995596473-05:00 tests/test_report_traits.py::test_pennycheck_fuel_gallons_kpi_matches_journal PASSED [ 12%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:14.996652857-05:00 tests/test_report_traits.py::test_pennycheck_scan_row_count_is_the_penny_day PASSED [ 16%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.003632387-05:00 tests/test_report_traits.py::test_daily_is_sendable_with_zero_weekly_markers PASSED [ 20%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.005389266-05:00 tests/test_report_traits.py::test_daily_rendered_markdown_has_no_weekly_structure PASSED [ 24%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.009515723-05:00 tests/test_report_traits.py::test_deliberately_leaked_daily_is_flagged_not_sendable PASSED [ 28%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.011120273-05:00 tests/test_report_traits.py::test_category_totals_reconcile_to_inside_sales[report_daily_fastime.json-Inside Sales] PASSED [ 32%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.012600555-05:00 tests/test_report_traits.py::test_category_totals_reconcile_to_inside_sales[report_weekly_fastime.json-Inside Sales] PASSED [ 36%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.013904967-05:00 tests/test_report_traits.py::test_unclassified_share_is_a_small_residual[report_daily_fastime.json] PASSED [ 40%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.015208130-05:00 tests/test_report_traits.py::test_unclassified_share_is_a_small_residual[report_weekly_fastime.json] PASSED [ 44%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.016531562-05:00 tests/test_report_traits.py::test_rendered_daily_categories_use_mj_taxonomy PASSED [ 48%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.018010954-05:00 tests/test_report_traits.py::test_rank_table_labels_its_comparison_basis PASSED [ 52%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.019285987-05:00 tests/test_report_traits.py::test_rank_deltas_are_bounded_for_staples PASSED [ 56%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.021052716-05:00 tests/test_report_traits.py::test_rank_arrows_reproduce_from_the_journal PASSED [ 60%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.022137560-05:00 tests/test_report_traits.py::test_daily_header_spells_out_correct_weekday PASSED [ 64%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.024502187-05:00 tests/test_report_traits.py::test_weekly_conversion_rows_carry_correct_weekday PASSED [ 68%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.026184357-05:00 tests/test_report_traits.py::test_all_weekday_date_pairs_are_internally_consistent PASSED [ 72%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.027665409-05:00 tests/test_report_traits.py::test_headline_reads_total_sales_on_every_surface[daily_md-$14,417.11] PASSED [ 76%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.029130110-05:00 tests/test_report_traits.py::test_headline_reads_total_sales_on_every_surface[weekly_md-$99,489.00] PASSED [ 80%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.031278408-05:00 tests/test_report_traits.py::test_sms_blocks_within_limits_and_never_trimmed[daily_md-daily] PASSED [ 84%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.032967498-05:00 tests/test_report_traits.py::test_sms_blocks_within_limits_and_never_trimmed[weekly_md-weekly] PASSED [ 88%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.034603969-05:00 tests/test_report_traits.py::test_sms_actions_block_keeps_whole_items_and_reply_prompt PASSED [ 92%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.046176562-05:00 tests/test_report_traits.py::test_store_events_are_configured_with_install_date PASSED [ 96%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.973740723-05:00 tests/test_report_traits.py::test_store_events_reach_the_synthesis_prompt PASSED [100%] [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978311687-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978320586-05:00 ------- generated xml file: /workspace/source/artifacts/junit-traits.xml ------- [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978325326-05:00 ================================ tests coverage ================================ [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978329446-05:00 _______________ coverage: platform linux, python 3.11.15-final-0 _______________ [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978333226-05:00 [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978337136-05:00 Coverage XML written to file /workspace/source/artifacts/coverage-traits.xml [pod/bootstrap-pr-report-check-pr244-jvhqk-traits-pod/step-pytest] 2026-07-12T18:10:15.978341726-05:00 ============================== 25 passed in 1.09s ==============================