-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_report_v3.py
More file actions
787 lines (686 loc) · 30.7 KB
/
Copy pathbuild_report_v3.py
File metadata and controls
787 lines (686 loc) · 30.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
"""Build commercial DOCX report for GEM ATS demo deliverables — V3 with all audit fixes.
Changes from V2:
- Heading hierarchy: L1 > L2 (was L1 > L3, skipping L2)
- Page breaks between Value Stories
- "CONFIGURED AND VERIFIED" replaces "ALL DELIVERED"
- 7 new VS3 screenshots integrated (scorecard, activity feed, canned responses, etc.)
- evidence_06 replaced with Mia Brown enriched profile
- Known Limitations consolidated into appendix
- Synthetic data disclaimer at top
- VS6 rediscovery narrative improved
- Screenshot count updated (31 total)
"""
import os
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
BASE = r"C:\Users\adm_r\Clients\GEM-BOOM"
OUT = os.path.join(BASE, "GEM_ATS_Demo_Deliverable_Report.docx")
IMG_DIR = os.path.join(BASE, "evidence_bordered")
doc = Document()
# Styles
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(10)
def add_heading_styled(text, level=1):
h = doc.add_heading(text, level=level)
for run in h.runs:
run.font.color.rgb = RGBColor(0x1A, 0x1A, 0x2E)
return h
def add_goal_quote(text):
p = doc.add_paragraph()
p.paragraph_format.left_indent = Inches(0.3)
p.paragraph_format.space_before = Pt(6)
p.paragraph_format.space_after = Pt(4)
run = p.add_run(f'"{text}"')
run.font.italic = True
run.font.size = Pt(10)
run.font.color.rgb = RGBColor(0x55, 0x55, 0x55)
return p
def add_body(text):
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(6)
run = p.add_run(text)
run.font.size = Pt(10)
return p
def add_image(filename, width=6.0):
path = os.path.join(IMG_DIR, filename)
if os.path.exists(path):
doc.add_picture(path, width=Inches(width))
last = doc.paragraphs[-1]
last.alignment = WD_ALIGN_PARAGRAPH.CENTER
last.paragraph_format.space_after = Pt(8)
else:
p = doc.add_paragraph(f"[Image not found: {filename}]")
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0x00, 0x00)
print(f"WARNING: Missing image: {filename}")
def add_click_path(text):
p = doc.add_paragraph()
run = p.add_run("Click path: ")
run.font.bold = True
run.font.size = Pt(9)
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
run2 = p.add_run(text)
run2.font.size = Pt(9)
run2.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
p.paragraph_format.space_before = Pt(0)
p.paragraph_format.space_after = Pt(12)
def add_separator():
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(4)
p.paragraph_format.space_after = Pt(4)
run = p.add_run("\u2500" * 80)
run.font.size = Pt(6)
run.font.color.rgb = RGBColor(0xCC, 0xCC, 0xCC)
# ================================================================
# HEADER / TITLE PAGE
# ================================================================
title = doc.add_heading('GEM ATS Demo \u2014 Deliverable Verification Report', level=0)
for run in title.runs:
run.font.color.rgb = RGBColor(0x1A, 0x1A, 0x2E)
p = doc.add_paragraph()
run = p.add_run(
"Client: TestBox | Platform: GEM (www.gem.com) | Date: February 8, 2026\n"
)
run.font.size = Pt(10)
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
run2 = p.add_run(
"Org: TestBox (thiago@testbox.com) | Environment: ATS-only (no CRM dependencies)"
)
run2.font.size = Pt(10)
run2.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
p2 = doc.add_paragraph()
run3 = p2.add_run("Status: ALL 6 VALUE STORIES \u2014 CONFIGURED AND VERIFIED")
run3.font.bold = True
run3.font.size = Pt(12)
run3.font.color.rgb = RGBColor(0x00, 0x7A, 0x33)
p2.paragraph_format.space_after = Pt(12)
p3 = doc.add_paragraph()
stats = (
"359 candidates \u2022 9 jobs \u2022 7 sources \u2022 "
"5 hires \u2022 31 screenshots \u2022 Zero CRM dependencies"
)
run4 = p3.add_run(stats)
run4.font.size = Pt(10)
run4.font.bold = True
p3.paragraph_format.space_after = Pt(8)
# Synthetic data disclaimer
p_disc = doc.add_paragraph()
p_disc.paragraph_format.left_indent = Inches(0.3)
p_disc.paragraph_format.space_before = Pt(4)
p_disc.paragraph_format.space_after = Pt(12)
run_disc = p_disc.add_run(
"Note: This environment contains synthetic data created for demonstration purposes. "
"All candidate names, companies, and contact information are fictitious. "
"Pipeline volumes and stage distributions are designed to showcase typical ATS "
"workflows at scale. Known data constraints are documented in the appendix."
)
run_disc.font.italic = True
run_disc.font.size = Pt(9)
run_disc.font.color.rgb = RGBColor(0x88, 0x88, 0x88)
# ================================================================
# TABLE OF CONTENTS (manual since python-docx doesn't support auto TOC)
# ================================================================
add_heading_styled("Table of Contents", level=1)
toc_items = [
"VS1 \u2014 AI Application Review for High-Volume Inbound",
"VS2 \u2014 Interview Scheduling at Scale",
"VS3 \u2014 Hiring Team Collaboration & Candidate Experience",
"VS4 \u2014 Executive Recruiting Visibility (Headcount / Pipeline Health)",
"VS5 \u2014 Source & Vendor ROI Optimization",
"VS6 \u2014 Talent Rediscovery inside ATS",
"Audit Summary",
"Appendix: Known Limitations",
]
for i, item in enumerate(toc_items, 1):
p = doc.add_paragraph()
run = p.add_run(f"{i}. {item}")
run.font.size = Pt(10)
p.paragraph_format.space_before = Pt(1)
p.paragraph_format.space_after = Pt(1)
doc.add_page_break()
# ================================================================
# VS1: AI APPLICATION REVIEW
# ================================================================
add_heading_styled("VS1 \u2014 AI Application Review for High-Volume Inbound", level=1)
add_heading_styled("Goal", level=2)
add_goal_quote("Show reviewers triaging large inbound pools efficiently")
add_body(
'Software Engineer job has 210 active candidates (232 total including rejected) '
'with 139 waiting in Application Review. "Start reviews (139)" button on Jobs list '
"launches a full 3-panel triage UI. Left panel lists candidates, center shows "
"profile/resume, right panel has candidate info + actions."
)
add_image("VS1_D1_high_volume_210_candidates.png")
add_click_path('ATS > Jobs > Software Engineer (R1) > "Start reviews (139)"')
add_heading_styled("ATS Features", level=2)
add_goal_quote("Job \u2192 Applications \u2192 Review workflow")
add_body(
'Review UI shows "To review (139)" and "Reviewed (0)" tabs. Header reads '
'"Reviewing Software Engineer (ID: R1) in Application review". '
"Resume viewer with zoom/download. Profile tab with Experience/Education."
)
add_image("VS1_D1_review_workflow_3panel.png")
add_click_path("ATS > Jobs > Software Engineer > Start reviews (139)")
add_goal_quote("Keywords/Filters")
add_body(
"Keywords button opens modal with resume keyword search, save/load keywords, and "
'filter options (1+ keyword / no keywords / all). Resume search bar: "Search resumes '
'(e.g. excel AND accounting)". Source filter shows 7 sources with candidate counts. '
"Additional filters: Referrals (20), Prev contacted (29), Seen (1), Recently rejected, "
'Multiple apps, Prev screened. Sort by Oldest first. Bulk action button. "Enable AI '
'ranking" button in review header.'
)
add_image("VS1_D1_keywords_filter_modal.png")
add_image("VS1_D5_source_filter_7sources.png")
add_click_path('Inside review > "Keywords" button | "Source" dropdown')
add_goal_quote("Start reviews")
add_body(
'Every open job shows "Start reviews (N)" on the Jobs list. '
"Also accessible from job detail page header and inside the pipeline card view."
)
add_image("VS1_D1_jobs_list_start_reviews.png")
add_goal_quote("Candidate profile review")
add_body(
"Enriched hero candidate profiles include Experience, Education, company, title, "
"school, location, certifications, and LinkedIn links. Below: Mia Brown showing "
"6+ years experience (Data Scientist at Meta, ML Engineer at Google), MS from MIT, "
"active reminder, and application details."
)
add_image("vs3_candidate_profile_mia_brown.png")
add_click_path("ATS > Candidates > click candidate name > Profile tab")
add_goal_quote("Move forward/reject decisions")
add_body(
'Green "Advance to Phone screen" button with dropdown for stage selection. '
'Red "Reject with message" button with options. Stage dropdown in header: '
"Application review \u2192 Phone screen \u2192 Onsite \u2192 Offer (4 navigable stages). "
"Left/right arrows to navigate candidates."
)
add_image("VS1_D1_stage_selector_dropdown.png")
add_goal_quote("Transition into interview steps")
add_body(
"Advance button moves candidates to Phone Screen (57 already there). "
"Interview plan configured: Phone Screen (30 min), Technical Interview (60 min), "
"Culture Fit (45 min). Full pipeline across 4 stages + Hired outcome: "
"139 \u2192 57 \u2192 13 \u2192 1 active offer \u2192 2 hired."
)
add_image("VS1_D1_full_pipeline_all_stages.png")
add_click_path("Job > Talent pipeline > Card view > Stages: All")
# Synthetic Data
add_heading_styled("Synthetic Data", level=2)
add_goal_quote(
"High-volume job with many applications across a spectrum of quality"
)
add_body(
"Software Engineer: 210 active / 232 total. Candidates range from basic profiles "
"to enriched hero candidates (Marcus Chen \u2013 Sr SW Eng at Stripe, "
"Mia Brown \u2013 Data Scientist at Meta with 6+ years at Meta/Google). Realistic funnel: "
"139 \u2192 57 \u2192 13 \u2192 1 active offer \u2192 2 hired. "
"6 open jobs for comparison."
)
add_goal_quote("Realistic resumes/attachments")
add_body(
"Every candidate has a Generated Resume. Marcus Chen has uploaded PDF resume "
"(via referral). In-app PDF viewer with zoom in/out and download."
)
add_goal_quote("Candidate tags/fields used for filtering")
add_body(
"7 sources across 4 source types: LinkedIn, Indeed, Github (Sourced); "
"LinkedIn Basic Jobs, Work at a Startup (External job board); "
"Direct referral (Referral); Company career site (Career site). "
"Enriched fields: company, title, school, location, LinkedIn links. "
"1\u20134 internal notes per hero candidate."
)
add_goal_quote("Applications distributed across stages")
add_body(
"4 pipeline stages + Hired outcome: Application Review (139) \u2192 "
"Phone Screen (57) \u2192 Onsite (13) \u2192 Offer (1) \u2192 Hired (2). "
"Realistic funnel with decreasing volume at each selection step."
)
doc.add_page_break()
# ================================================================
# VS2: INTERVIEW SCHEDULING
# ================================================================
add_heading_styled("VS2 \u2014 Interview Scheduling at Scale", level=1)
add_heading_styled("Goal", level=2)
add_goal_quote(
"Demo scheduling at volume \u2014 queue management, interviewer load "
"balancing, availability requests"
)
add_body(
"Scheduling Queue has 154 candidates across 7 pages. 9 interviewers listed "
"with workload distribution. 1 upcoming interview scheduled (Leila Robinson \u2013 "
"Feb 11 \u2013 Onsite Technical Interview). Training program configured for "
"interviewer onboarding."
)
add_image("VS2_D2_scheduling_queue_154.png")
add_click_path("Scheduling > Scheduling Queue")
add_heading_styled("ATS Features", level=2)
add_goal_quote("Scheduling Queue with candidates awaiting scheduling")
add_body(
"154 candidates in queue with columns: Candidate, Status, Job, Stage, "
'Interview date(s). "Request availability" button on each candidate card. '
"7 pages of candidates to schedule."
)
add_goal_quote("Interviewer management & load balancing")
add_body(
"9 team members on Interviewers page with email, trained-on, and tags columns."
)
add_image("VS2_D2_interviewers_9_members.png")
add_click_path("Scheduling > Interviewers")
add_goal_quote("Interview plan per job (stages, durations, panels)")
add_body(
"Each job has configured interview plan: Phone Screen (30 min), Technical "
"Interview (60 min), Culture Fit (45 min). Visible on job detail page under "
"Interview Plan tab."
)
add_goal_quote("My Interviews page (upcoming + completed scorecards)")
add_body(
"My Interviews shows 1 upcoming: Leila Robinson \u2013 Feb 11 \u2013 "
"Onsite Technical Interview \u2013 Product Manager R4. "
"1 scorecard submitted with recommendation: Yes."
)
add_image("VS2_D2_my_interviews_upcoming.png")
add_click_path("ATS > My Interviews")
add_goal_quote("Training Programs for interviewer onboarding")
add_body(
'1 training program: "Technical Interview" with Shadow (2 sessions) and '
"Reverse Shadow (1 session) phases. Columns: Eligibility, Trainees, "
"Graduates, Training phases."
)
add_image("VS2_D2_training_programs.png")
add_click_path("Scheduling > Training Programs")
doc.add_page_break()
# ================================================================
# VS3: HIRING TEAM COLLABORATION
# ================================================================
add_heading_styled(
"VS3 \u2014 Hiring Team Collaboration & Candidate Experience", level=1
)
add_heading_styled("Goal", level=2)
add_goal_quote(
"Show scorecards, structured feedback, and debrief readiness"
)
add_body(
"13+ candidates have internal notes (1\u20134 each) with @mention capability. "
"Scorecard template configured and 1 scorecard submitted (Leila Robinson: "
'recommendation "Yes"). 3 canned response templates for candidate '
"communication. Offer letter template with 3 active draft offers. "
"4 reminders set. 2 review requests between team members."
)
add_heading_styled("ATS Features", level=2)
add_goal_quote("Internal notes with @mentions on candidate profiles")
add_body(
"Activity Feed on candidate profiles shows chronological history of all interactions: "
"notes, emails, stage movements, scorecards, and applications. Below: Mia Brown\u2019s "
"Activity Feed with 4 entries including detailed interview feedback, referral context, "
"and a private note about salary discussions."
)
add_image("vs3_activity_feed_mia_brown.png")
add_click_path("ATS > Candidates > Mia Brown > Activity Feed tab")
add_body(
'Notes section on every candidate profile with "@mention someone to notify '
'them" placeholder. Private toggle for sensitive notes. Post button. '
"Note count badges visible on candidate cards (1\u20134 per candidate)."
)
add_goal_quote("Scorecard submitted with structured feedback")
add_body(
"Below: Leila Robinson\u2019s Onsite stage showing submitted scorecard from "
"Thiago Rodrigues with recommendation \u201cYes\u201d on Technical Interview, "
"and Gabriel Taufer\u2019s Culture Fit interview awaiting feedback. "
"This demonstrates multi-interviewer panel coordination."
)
add_image("vs3_scorecard_submitted.png")
add_click_path("ATS > My Interviews > Leila Robinson > Onsite stage panel")
add_goal_quote("Scorecard templates for structured feedback")
add_body(
'"Technical Interview Scorecard" template (Published). Customizable rating scale '
"available via \u201cCustomize scorecard ratings\u201d button."
)
add_image("vs3_scorecard_template.png")
add_click_path("Templates > Interviews & scheduling > Scorecards")
add_goal_quote("Interview templates for standardized process")
add_body(
'"Technical Phone Screen" interview template (Published, 45 min). '
"Linked to job interview plans for consistent candidate evaluation."
)
add_image("vs3_interview_template.png")
add_click_path("Templates > Interviews & scheduling > Interviews")
add_goal_quote("Canned response templates for candidate communication")
add_body(
"3 canned responses configured with merge fields for personalization:\n"
'\u2022 "Interview Scheduling" \u2014 schedule interview with {{first_name}} and {{job_opening}} tokens\n'
'\u2022 "Application Received" \u2014 acknowledgment of application\n'
'\u2022 "Rejection \u2013 General" \u2014 standard rejection with professional tone'
)
add_image("vs3_canned_responses.png")
add_click_path("Templates > Messages > Canned responses")
add_goal_quote("Offer letter templates")
add_body(
'"Standard Offer Letter" template (Active, created Feb 8, 2026). '
"Downloadable template with offer settings. "
"3 draft offers active: $165K (SW Eng), $145K (UX Designer), $185K (DevOps). "
"All in San Francisco."
)
add_image("vs3_offer_letter_template.png")
add_click_path("Templates > Offers > Offer letters")
add_goal_quote("Reminders for follow-ups")
add_body(
"4 reminders set across candidates: 1 due today (Marcus Chen \u2014 \u201cReview "
"referral application and schedule phone screen\u201d), 3 future-dated (including "
"Mia Brown \u2014 \u201cFollow up on offer acceptance \u2014 competing Google offer at "
"$180K\u201d, due Feb 12). To-do page shows Reminders (1 Due)."
)
add_goal_quote("Review requests between team members")
add_body(
"2 review requests sent: Drew Regitsky + Nick Bushak \u2192 Gabriel Taufer. "
"Enables peer feedback before key hiring decisions."
)
# Candidate card with note badges
add_heading_styled("Candidate Card Context", level=2)
add_body(
"Pipeline card view shows note count badges on candidate cards. Below: "
"Mia Brown in Offer stage with 4 internal notes badge, source attribution "
'(LinkedIn), and status "Offer needs to be sent."'
)
add_image("VS1_D3_offer_stage_mia_brown.png")
doc.add_page_break()
# ================================================================
# VS4: EXECUTIVE RECRUITING VISIBILITY
# ================================================================
add_heading_styled(
"VS4 \u2014 Executive Recruiting Visibility (Headcount / Pipeline Health)",
level=1,
)
add_heading_styled("Goal", level=2)
add_goal_quote(
"Give executive stakeholders real-time visibility into pipeline health, "
"headcount tracking, and hiring progress"
)
add_body(
"2 dashboards with live KPI widgets. Pipeline Analytics with full funnel: "
"425 \u2192 165 (39%) \u2192 52 (32%) \u2192 12 (23%) \u2192 5 (42%). "
"4 pre-built reports. 8 openings tracked across 4 lifecycle states."
)
add_image("VS4_D4_recruiting_health_kpis.png")
add_click_path('Talent Compass > Dashboards > "Recruiting health"')
add_heading_styled("ATS Features", level=2)
add_goal_quote("Dashboards with recruiting KPIs")
add_body(
'"Recruiting health" dashboard (favorited): Total hires = 5, '
"Avg time to hire = 1 day, Current open jobs = 6. Sections: Overview, "
"By recruiter, By office, KPIs, Referrals, Pipeline metrics. "
'"Hiring Overview Q1 2026" dashboard also available.'
)
add_image("VS4_D4_dashboards_list.png")
add_goal_quote("Pipeline Analytics with funnel visualization")
add_body(
"Full funnel chart: 425 \u2192 165 (39%) \u2192 52 (32%) \u2192 12 (23%) "
"\u2192 5 (42%). Per-job breakdown for all 6 open jobs."
)
add_image("VS4_D4_pipeline_analytics_funnel.png")
add_body(
"Dashboard passthrough rates by stage: 7% out of App Review, "
"100% Phone Screen, 100% Onsite, 100% Offer."
)
add_image("VS4_D4_passthrough_rates.png")
add_click_path("Talent Compass > Pipeline Analytics")
add_goal_quote(
"Reports (Hire Rate, Rejection Reasons, Recruiter Activity, Time to Hire)"
)
add_body(
"4 pre-built reports available: Hire Rate by Source, Rejection Reasons, "
"Recruiter Activity, Time to Hire by Department."
)
add_image("VS4_D4_reports_4_prebuilt.png")
add_click_path("Talent Compass > Reports")
add_goal_quote("Openings / headcount tracking")
add_body(
"8 openings across 4 lifecycle states: Open (1), Draft (1), Closed/filled (5), "
"Closed/unfilled (1)."
)
add_image("VS4_D4_openings_open_draft.png")
add_body(
"Filled openings show candidate assigned: OP1 SW Eng \u2192 Sophia Brown, "
"OP2 SW Eng \u2192 Charlotte Miller, OP3 PM \u2192 Emma Nakamura, "
"OP5 UX \u2192 Kenji Thompson, OP6 DevOps \u2192 Andrew Moore."
)
add_image("VS4_D4_openings_filled_headcount.png")
add_click_path("ATS > Openings > toggle between Open, Draft, Closed tabs")
doc.add_page_break()
# ================================================================
# VS5: SOURCE & VENDOR ROI
# ================================================================
add_heading_styled("VS5 \u2014 Source & Vendor ROI Optimization", level=1)
add_heading_styled("Goal", level=2)
add_goal_quote(
"Help recruiting ops measure and optimize spend across sources and job boards"
)
add_body(
"ROI Calculator fully populated: US$2,127 total cost, "
'US$7/application, US$532/hire. "Lowest cost per hire" and "Highest '
'overall cost" comparison charts. "Manage expenses" button for cost input.'
)
add_image("VS5_D5_roi_calculator_full.png")
add_click_path("Talent Compass > ROI Calculator")
add_heading_styled("ATS Features", level=2)
add_goal_quote("ROI Calculator with cost per hire and cost per application")
add_body(
"Per-source breakdown:\n"
"\u2022 LinkedIn (Sourced): US$532, 141 apps, US$4/app, 3 hired, US$177/hire\n"
"\u2022 Indeed (Sourced): US$266, 65 apps, US$4/app\n"
"\u2022 Github (Sourced): US$53, 23 apps, US$2/app\n"
"\u2022 LinkedIn Basic Jobs (External): US$128, 39 apps, US$3/app, 1 hired, US$128/hire\n"
"\u2022 Work at a Startup (External): US$85, 24 apps, US$4/app\n"
"\u2022 Direct referral: 61 apps, 1 hired (organic \u2014 no cost)\n"
"\u2022 Company career site: 72 apps (organic \u2014 no cost)\n\n"
"Total: US$2,127 across 292 attributed applications (of 425 total). "
"Overall: US$7/app, US$532/hire (4 hires with cost attribution)."
)
add_goal_quote("Source distribution and effectiveness tracking")
add_body(
"7 distinct sources visible in review workflow source filter and on candidate cards. "
"4 source types: Sourced, External job board, Referral, Career site. "
"Source column in pipeline table view. Pipeline Analytics shows source-to-hire conversion."
)
doc.add_page_break()
# ================================================================
# VS6: TALENT REDISCOVERY
# ================================================================
add_heading_styled("VS6 \u2014 Talent Rediscovery inside ATS", level=1)
add_heading_styled("Goal", level=2)
add_goal_quote(
"Enable recruiters to rediscover past candidates \u2014 silver medalists, "
"previously screened talent, prior applicants"
)
add_body(
"Candidates page shows 359 total candidates searchable with filters. "
'3 curated folders including "Silver Medalists \u2013 Future Roles" (2 items). '
"Resume search with boolean operators. Card/Compact/Table views. "
"Enriched hero candidates with full work history for quick evaluation."
)
add_image("VS6_D6_candidates_359_all_stages.png")
add_click_path("ATS > Candidates")
add_heading_styled("ATS Features", level=2)
add_goal_quote("Candidates page with searchable database")
add_body(
'"Showing 251 of 359 candidates" with activity-based filtering (past 45 days). '
"Filter by Status, Filter by Milestones, Add filter button. "
'"Show rejected candidates" checkbox. Card, Compact, and Table views.'
)
add_goal_quote("Folders for organizing talent pools")
add_body(
"3 folders:\n"
"\u2022 Top Engineering Candidates (3 items) \u2014 curated list of strongest technical talent\n"
"\u2022 Q1 2026 Hiring Pipeline (3 items) \u2014 priority candidates for current quarter\n"
"\u2022 Silver Medalists \u2013 Future Roles (2 items) \u2014 strong candidates not selected "
"for original role, flagged for future opportunities"
)
add_image("VS6_D6_folders_silver_medalists.png")
add_click_path("Home > Folders")
add_goal_quote("Resume search and filters for rediscovery")
add_body(
'Resume search: "Search resumes (e.g. excel AND accounting)" in review UI. '
"Filters: Prev contacted (29), Prev screened, Multiple apps, Source, "
"Referrals (20), Recently rejected, Seen. Sort options. Bulk action."
)
add_goal_quote("Enriched profiles for candidate evaluation")
add_body(
"Hero candidates with full profiles for quick rediscovery evaluation:\n"
"\u2022 Marcus Chen \u2014 Sr Software Engineer at Stripe, AWS/Oracle certifications\n"
"\u2022 Mia Brown \u2014 Data Scientist at Meta (prev Google), MIT MS Computer Science\n"
"\u2022 Charlotte Miller \u2014 Software Engineer at Airbnb\n"
"\u2022 Sophia Brown \u2014 Full Stack Developer at Adobe\n"
"\u2022 Ella Johnson \u2014 UX Designer at Uber\n"
"\u2022 Matthew Robinson \u2014 UX Designer at Meta\n"
"\u2022 Ava Taylor \u2014 Data Scientist at Salesforce\n"
"\u2022 Harper Davis \u2014 QA Engineer at Zoom\n\n"
"LinkedIn profile links on candidate cards. Pipeline table view "
"with company, title, and stage columns."
)
add_image("VS6_D6_pipeline_table_enriched.png")
add_click_path("Jobs > Software Engineer > Talent pipeline > Table view")
add_heading_styled("Rediscovery Scenario", level=2)
add_body(
"Example workflow:\n"
"1. Recruiter opens Silver Medalists folder and finds a candidate who reached "
"Onsite for Software Engineer but was not selected.\n"
"2. With the new Sr Software Engineer opening now active, the recruiter views "
"the candidate\u2019s prior application history and internal notes from the "
"previous interview panel.\n"
"3. The recruiter adds the candidate to the new job pipeline using "
"\u201cCreate new application\u201d on the candidate profile.\n"
"4. The candidate is scheduled for a Phone Screen via the Scheduling Queue "
"\u2014 all within the ATS, without CRM sequences or outreach campaigns.\n\n"
"Supporting ATS features: Prev screened and Multiple apps filters in the "
"review workflow surface additional candidates with prior engagement. "
"Activity Feed preserves full interaction history across applications."
)
doc.add_page_break()
# ================================================================
# AUDIT SUMMARY
# ================================================================
add_heading_styled("Audit Summary", level=1)
# Summary table
table = doc.add_table(rows=7, cols=3)
table.style = "Light Shading Accent 1"
headers = ["Value Story", "Status", "Key Evidence"]
for i, h in enumerate(headers):
table.rows[0].cells[i].text = h
for p in table.rows[0].cells[i].paragraphs:
for r in p.runs:
r.font.bold = True
r.font.size = Pt(9)
data = [
(
"VS1: AI Application Review",
"VERIFIED",
"210 active candidates, 139 in review, 7 sources, keywords/filters, full pipeline",
),
(
"VS2: Interview Scheduling",
"VERIFIED",
"154 in queue, 9 interviewers, 1 upcoming, training program, interview plans",
),
(
"VS3: Team Collaboration",
"VERIFIED",
"13+ notes, 1 scorecard submitted, 3 canned responses, offer template, 4 reminders",
),
(
"VS4: Executive Visibility",
"VERIFIED",
"2 dashboards, funnel 425\u21925, 8 openings (4 states), 4 reports",
),
(
"VS5: Source & Vendor ROI",
"VERIFIED",
"US$2,127 total, 7 sources in 4 types, cost-per-hire by channel, ROI charts",
),
(
"VS6: Talent Rediscovery",
"VERIFIED",
"359 candidates, 3 folders incl Silver Medalists, resume search, enriched profiles",
),
]
for i, (vs, status, evidence) in enumerate(data):
row = table.rows[i + 1]
row.cells[0].text = vs
row.cells[1].text = status
row.cells[2].text = evidence
for cell in row.cells:
for p in cell.paragraphs:
for r in p.runs:
r.font.size = Pt(9)
p_end = doc.add_paragraph()
p_end.paragraph_format.space_before = Pt(16)
run_end = p_end.add_run(
"All 6 value stories configured and verified. "
"Demo environment ready for client presentation."
)
run_end.font.bold = True
run_end.font.size = Pt(11)
doc.add_page_break()
# ================================================================
# APPENDIX: KNOWN LIMITATIONS
# ================================================================
add_heading_styled("Appendix: Known Limitations", level=1)
add_body(
"The following are known data constraints inherent to the synthetic demo "
"environment. These are documented in the SOW (sections 6.0 and 7.0) "
"and do not affect the functional completeness of the 6 value stories."
)
add_heading_styled("Time-to-Hire KPI", level=2)
add_body(
"Average time to hire shows 1 day (vs 44-day industry benchmark) because "
"all synthetic candidates were processed in a single session. Stage "
"transition timestamps cannot be backdated until Gem engineering delivers "
"the committed endpoint. Once available, this KPI will reflect realistic "
"hiring timelines."
)
add_heading_styled("Dashboard Passthrough Rates", level=2)
add_body(
"Dashboard passthrough rates (7%, 100%, 100%, 100%) come from a recent "
"time window widget. The 100% in middle stages is an artifact of synthetic "
"batch processing: all candidates were moved between stages in a single "
"session. The Pipeline Analytics funnel (39%, 32%, 23%, 42%) shows "
"cumulative conversion across all time and is the authoritative metric."
)
add_heading_styled("ROI Calculator Source Mapping", level=2)
add_body(
"The GEM ROI Calculator auto-matches expenses to source types. Some expense "
'entries appear as "(source type not found)" when GEM cannot resolve the '
"mapping. These unmapped entries account for US$1,063 of the US$2,127 total. "
"The per-source metrics (US$4/app LinkedIn, US$2/app Github, etc.) are "
"calculated by GEM using only the matched portions."
)
add_heading_styled("Source Filter Counts", level=2)
add_body(
"Source counts in the review filter dropdown (LinkedIn 29, Career site 23, "
"Indeed 13, Direct referral 13, LinkedIn Basic Jobs 11, Work at a Startup 7, "
"Github 4 = 100) reflect candidates with source attribution in the current "
"review queue. The remaining 39 of 139 candidates have no source assigned."
)
add_heading_styled("Scorecard Volume", level=2)
add_body(
"1 scorecard is submitted (Thiago Rodrigues \u2192 Leila Robinson, "
"recommendation: Yes). Additional scorecards with varied ratings (Strong "
"Yes / No / Maybe) require more completed interviews, which depend on "
"calendar integration configuration. The scorecard template and submission "
"workflow are fully functional."
)
add_heading_styled("Candidate Experience/Education", level=2)
add_body(
"Experience and Education fields are populated on enriched hero candidates "
"(Mia Brown, Charlotte Miller, Sophia Brown, etc.) via GEM profile data. "
"Some candidates show \u201cNo work history available\u201d because GEM "
"sources this data from LinkedIn profiles, which are not always fully synced "
"in the TestBox environment."
)
# Save
doc.save(OUT)
print(f"Report saved: {OUT}")
print(f"Total images in evidence_bordered: {len(os.listdir(IMG_DIR))}")