# LFCS EOD Summary

## When to use

Rocky says: "EOD summary", "today's summary", "wrap up", or `/lfcs-eod-summary`.
Also runs at 17:00 daily via cron.

## Procedure

For each active job — check BOTH `lfcs.jobs_root/Ongoing Jobs/` AND `lfcs.jobs_root/Upcoming/` (jobs with `start_date` within ±7 days are active; also check jobs manually flagged as active). **Always check `Upcoming/` even if `Ongoing Jobs/` is empty or absent** — jobs just mobilised often live in Upcoming (e.g. Hornsby).

1. **Identify the job** — scan `Upcoming/` and `Ongoing Jobs/` directories. Job may still be in Upcoming if not formally promoted. Hornsby is the known pattern: active contract, RFIs sent, programme loaded, but folder still in Upcoming.
2. **Read today's diary** — check BOTH:
   - `<job>/07 - Site Documents/07d - Daily Diary/YYYY-MM-DD.md` (job-specific diary)
   - `/home/ccuser/opsman-work/daily/YYYY-MM-DD.md` (shared ops log at the ops workspace root — Hermes captures live site activity here with timestamps and tasks; may have Rocky's work even when job-specific diary is absent)
   If missing from both → flag "no diary entry today" but still continue.
3. **Read Job-Tracker** — check for `Job-Tracker.md` first. If not found, look for `Job Tracker - <job>.xlsx` (Excel format). If `.xlsx`:
   - Use `python3.12` (system Python, NOT the cron venv's Python 3.11 which lacks `openpyxl`)
   - Read the `Labor Hours` sheet for today's hours rows; `Materials Receipts` for materials
   - All-hours-zero in the Excel is a real finding, not a read error — report it as such
4. **Run docket check** (see docket-check reference).
5. **Read RFIs** — `<job>/06 - Correspondence/06b - RFIs/_REGISTER.md`, count Cat A still Pending.
6. **Read programme** — `<job>/04 - Programme and Scheduling/programme-24wk.md` — tomorrow's planned activity.

## Output format

Tight 5-7 line summary per job. Use **🔴 red-text** (Telegram `‎` + bold) for CRITICAL flags — missing docket is always CRITICAL.

**CRITICAL docket flag format** (always use this when missing):
```
🔴 DOCKET MISSING — no signed docket = no invoice line.
```

**Docket found format** (happy path):
```
📋 Docket: ✅ signed (07a/YYYY-MM-DD-signed.*)
```

**Full EOD example — docket missing:**
```
🔧 EOD 2026-06-05 — Hornsby (01-2275):
• ⏱ Hours today: 0 — Job-Tracker blank
• 📸 Photos today: None
• 📦 Materials in: None recorded
• 🔴 DOCKET MISSING — no signed docket = no invoice line.
• 📅 Tomorrow: Zone 3 pour day 4 — confirm pump, crew, HammerTech induction
• 🔴 Chase: Claim 1 (11 days overdue), 10× Cat A RFIs, sub-base handover
```

**Full EOD example — docket OK:**
```
🔧 EOD 2026-04-30 — Hornsby (01-2275):
• Diary: 1 entry, 3 photos saved to 07b
• ⏱ Hours: Tomek 8.0h, Filip 8.0h, Rocky 6.0h (total $1,624)
• 📦 Materials in: 30 sheets formply, SL72 mesh starter pack
• 📋 Docket: ✅ signed (07a/2026-04-30-signed.jpg)
• 📅 Tomorrow: Stair forming Day 2; pump confirmed for Fri
• ⚠️ RFIs: 4 Cat A still pending (sub-base, pump, mix, induction)
```

## Pitfalls

- **Job-Tracker.md empty (0 lines) is a real finding.** Report it explicitly — "no hours logged today." Do not treat it as a read error or skip the hours section. An empty tracker means nothing has been recorded for today (or all week), not that the file failed to load.
- **Ongoing Jobs/ and job folder names have spaces** — always quote paths in shell commands: `"Ongoing Jobs/01-2275 - HPE Field of Play Hornsby/"`. A bare path will silently return nothing.
- **Job may live in both Ongoing AND Upcoming.** Always search using `search_files` with a broad path (`/home/ccuser/opsman-work/Jobs/`) and a date pattern first — do not hardcode the subfolder path. Read the FIRST matching file found, not a later copy.
- **Empty docket folder (exit 0) ≠ no activity day.** If `ls <docket-dir>/YYYY-MM-DD-signed.*` returns exit 0 with zero files, the docket folder exists but is empty today. Report as "docket missing," not "folder not found." See docket-check reference.
- Don't repeat info Rocky already saw earlier today. Just deltas.
- On the cron-fired version (17:00 daily): if no activity at all AND no docket at risk, reply with one line ("No site activity today. [Reason if known.]") rather than a long empty template.
- Leverage the docket-check skill — don't reimplement.
- If multiple ongoing jobs, summarise each separately, separated by blank line.

## Non-working days (weekends, public holidays)

If today has no diary entry AND no hours logged AND no docket — the job may still have an **open at-risk docket from the last working day**. Before going silent:

1. Check `<job>/07 - Site Documents/07a - Dockets/` for any `*-signed.*` files.
2. If the most recent docket is from a recent working day and is missing → surface it in the EOD summary as a CRITICAL flag, even though "today" has no activity.
3. The summary format on a silent weekend day becomes:
   ```
   🔧 EOD — [Job name] | [Today, e.g. Sat 2 May]
   • No site activity today (weekend). Last site day: Fri 1 May.
   • ⏱ Last day hours: [who] [hours] — logged in Job-Tracker
   • 🔴 DOCKET MISSING — 01 May not photographed. No signed docket = no invoice line.
   • 📅 Next on: Mon [date]
   • ⚠️ Chase: [client contact] for retro docket sign-off
   ```
4. Only suppress the summary if: no docket from any recent working day is missing AND no other open items exist.

## Verification

After replying:
1. Reply ≤ 7 lines per active job. If longer, trim before sending.
2. Each numeric in the summary (hours, $) must trace back to a specific row in `Job-Tracker.md` — if you can't cite the row, mark "(unverified)" rather than guess.
3. Cron-fired version: confirm the trigger fired at ~17:00 Sydney time by checking `~/.hermes/cron/` last-run log; if late by >30 min, append a note to today's diary.
4. On a weekend/holiday silent day: confirm you checked for the last working day's docket before suppressing. If the last docket is missing → do NOT suppress, surface the CRITICAL flag.