chore: sync working tree changes

This commit is contained in:
root
2026-08-08 13:06:45 -04:00
parent df9fca8631
commit 0bc671b965
3 changed files with 784 additions and 0 deletions
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env python3
"""
VerdictTank PDF Generator - fills template with verdict data, renders to PDF via WeasyPrint.
Usage: python3 generate-pdf.py [--data data.json] [--output verdict-report.pdf]
"""
import json, os, sys, re
from datetime import datetime
from weasyprint import HTML
TEMPLATE_PATH = os.path.join(os.path.dirname(__file__), "pdf-template.html")
OUTPUT_DIR = "/var/www/verdicttank/reports"
EM_DASH_PATTERN = re.compile(r'\u2014|\u2013') # em dash and en dash
def clean(text):
"""Strip all em/en dashes - replace with hyphen."""
return EM_DASH_PATTERN.sub('-', str(text))
def score_bar(score):
if score is None:
return '<span class="score-bar score-na" style="width:80px"></span> N/A'
width = score * 8
if score <= 3:
cls, label = "score-critical", "Critical"
elif score <= 5:
cls, label = "score-warning", "Weak"
elif score <= 7:
cls, label = "score-ok", "Adequate"
else:
cls, label = "score-good", "Strong"
return clean(f'<span class="score-bar {cls}" style="width:{width}px"></span> {score}/10 - {label}')
def flaw_label(severity):
mapping = {
"Existential": "flaw-existential",
"Structural": "flaw-structural",
"Financial": "flaw-financial",
"Operational": "flaw-operational",
"Brand-fatal": "flaw-existential",
}
cls = mapping.get(severity, "flaw-structural")
return clean(f'<span class="flaw-label {cls}">{severity}</span>')
def build_score_rows(scores):
rows = ""
for dim in scores:
rows += clean(f'<tr><td class="dim">{dim["name"]}</td><td>{score_bar(dim["score"])}</td><td style="font-size:8.5pt;color:#555">{dim["note"]}</td></tr>\n')
return rows
def build_flaws(flaws):
html = ""
for i, f in enumerate(flaws, 1):
html += clean(f'''<div class="flaw-box">
<span class="flaw-num">#{i}</span> <strong>{f["title"]}</strong> {flaw_label(f.get("severity", "Structural"))}
<p style="margin-top:4px;font-size:9pt;color:#555;">{f["detail"]}</p>
</div>\n''')
return html
def build_judge_cards(judges):
"""Build judge cards - uses data-provided names (expected: Judge 1, Judge 2, Judge 3)."""
html = ""
for i, j in enumerate(judges):
verdict_html = ""
if j.get("verdict") == "upheld":
verdict_html = '<span class="judge-verdict upheld">UPHOLDS</span>'
else:
verdict_html = clean(f'<span class="judge-verdict overruled">{j.get("verdict", "DISAGREES")}</span>')
confidence = j.get("confidence", "")
conf_html = f'<span class="judge-confidence">{confidence} confidence</span>' if confidence else ""
html += clean(f'''<div class="judge-card">
<div class="judge-name">{j["name"]}</div>
{verdict_html}
{conf_html}
<p class="judge-note">{j.get("note", "")}</p>
</div>\n''')
return html
def build_strengths(items):
return "\n".join(clean(f"<li>{s}</li>") for s in items)
def build_action_rows(actions):
html = ""
for a in actions:
p = a["priority"]
cls = f"priority-p{p}" if p in ("0", "1", "2") else ""
html += clean(f'<tr><td class="priority {cls}">P{p}</td><td><strong>{a["action"]}</strong></td><td style="font-size:8.5pt;color:#555">{a["why"]}</td><td style="font-size:8.5pt;color:#999">{a["effort"]}</td></tr>\n')
return html
def build_research(data):
html = ""
for r in data:
html += clean(f'''<div class="finding">
<div class="finding-label">{r["label"]}</div>
<div class="finding-text">{r["text"]}</div>
<div class="finding-source">Source: {r.get("source", "Research sweep")}</div>
</div>\n''')
return html
def build_competitor_rows(competitors):
html = ""
for c in competitors:
html += clean(f'<tr><td><strong>{c["name"]}</strong></td><td style="font-size:8.5pt">{c["strengths"]}</td><td style="font-size:8.5pt;color:#cc0000">{c["gaps"]}</td><td style="font-size:8pt;color:#999">{c["threat"]}</td></tr>\n')
return html
def build_judge_notes(judges):
"""Judge notes - uses data-provided judge names, no model identifiers."""
html = ""
for i, j in enumerate(judges):
if j.get("dissent"):
html += clean(f'''<div style="margin-bottom:12px">
<strong>{j["name"]}:</strong> {j["dissent"]}
</div>\n''')
else:
html += clean(f'''<div style="margin-bottom:12px">
<strong>{j["name"]}:</strong> No dissent. Agreed with findings and scoring without material deviation.
</div>\n''')
return html
def build_citations(citations):
html = ""
for i, c in enumerate(citations, 1):
url_html = f' <a href="{c["url"]}">{c["url"]}</a>' if c.get("url") else ""
html += clean(f'<div class="citation">[{i}] {c["text"]}{url_html}</div>\n')
return html
def fill_template(data):
with open(TEMPLATE_PATH, "r") as f:
template = f.read()
judges = data.get("judges", [])
replacements = {
"{{PROPOSAL_NAME}}": clean(data.get("proposal_name", "Untitled Proposal")),
"{{SUBMITTER_NAME}}": clean(data.get("submitter_name", "Unknown")),
"{{REVIEW_DATE}}": clean(data.get("review_date", datetime.now().strftime("%B %d, %Y"))),
"{{REVIEW_ID}}": clean(data.get("review_id", "VT-" + datetime.now().strftime("%Y%m%d-%H%M"))),
"{{EXECUTIVE_SUMMARY}}": clean(data.get("executive_summary", "")),
"{{SCORE_ROWS}}": build_score_rows(data.get("scores", [])),
"{{FATAL_FLAWS}}": build_flaws(data.get("fatal_flaws", [])),
"{{JUDGE_CARDS}}": build_judge_cards(judges),
"{{JUDGE_MAJORITY_VERDICT}}": clean(data.get("judge_majority_verdict", "NO CONSENSUS")),
"{{JUDGE_AGREEMENT}}": str(data.get("judge_agreement", 0)),
"{{JUDGE_TOTAL}}": str(len(judges)),
"{{STRENGTHS}}": build_strengths(data.get("strengths", [])),
"{{RESEARCH_FINDINGS}}": build_research(data.get("research", [])),
"{{COMPETITOR_ROWS}}": build_competitor_rows(data.get("competitors", [])),
"{{ACTION_ROWS}}": build_action_rows(data.get("action_plan", [])),
"{{JUDGE_NOTES}}": build_judge_notes(judges),
"{{CITATIONS}}": build_citations(data.get("citations", [])),
}
for placeholder, value in replacements.items():
template = template.replace(placeholder, value)
# Kill any remaining unreplaced placeholders
template = re.sub(r'\{\{[A-Z_]+\}\}', 'N/A', template)
return template
def generate(data_path, output_path=None):
with open(data_path, "r") as f:
data = json.load(f)
html = fill_template(data)
if not output_path:
os.makedirs(OUTPUT_DIR, exist_ok=True)
client = data.get("submitter_name", "Client")
safe_client = re.sub(r'[^a-zA-Z0-9]', '', client)
if not safe_client:
safe_client = "Client"
output_path = os.path.join(OUTPUT_DIR, f"{safe_client}-VerdictTank-Report.pdf")
HTML(string=html).write_pdf(output_path)
return output_path
if __name__ == "__main__":
import argparse
ap = argparse.ArgumentParser()
ap.add_argument("--data", required=True, help="JSON data file")
ap.add_argument("--output", help="Output PDF path")
args = ap.parse_args()
path = generate(args.data, args.output)
print(f"PDF generated: {path}")
+509
View File
@@ -0,0 +1,509 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
@page {
size: letter;
margin: 0.75in 0.85in;
@bottom-center {
content: "VerdictTank - a product of IT Pro Partner | Page " counter(page);
font-family: Inter, -apple-system, sans-serif;
font-size: 8pt;
color: #999;
}
}
@page :first {
@bottom-center {
content: none;
}
margin-top: 1.5in;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 10pt;
line-height: 1.55;
color: #1a1a1a;
}
/* ============ COVER PAGE ============ */
.cover {
text-align: center;
page-break-after: always;
padding-top: 1in;
}
.cover .logo { font-size: 64px; line-height: 1; color: #cc0000; margin-bottom: 20px; }
.cover .logo-emoji { display: block; width: 72px; height: 72px; font-size: 64px; line-height: 1; color: #cc0000; margin-bottom: 20px; }
.cover h1 {
font-size: 28pt;
font-weight: 800;
letter-spacing: -0.03em;
color: #0a0a0a;
margin-bottom: 6px;
}
.cover .subtitle {
font-size: 13pt;
color: #666;
font-weight: 400;
margin-bottom: 32px;
}
.verdict-badge {
display: inline-block;
padding: 12px 32px;
border-radius: 12px;
font-size: 16pt;
font-weight: 800;
letter-spacing: -0.02em;
margin-bottom: 28px;
}
.verdict-no-go { background: #fef2f2; color: #cc0000; border: 2px solid #cc0000; }
.verdict-cond-go { background: #fff7ed; color: #ea580c; border: 2px solid #ea580c; }
.verdict-go { background: #f0fdf4; color: #16a34a; border: 2px solid #16a34a; }
.cover .meta {
font-size: 10pt;
color: #999;
margin-top: 20px;
line-height: 1.8;
}
.cover .meta strong { color: #555; font-weight: 600; }
.cover-footer {
position: absolute;
bottom: 0.75in;
left: 0;
right: 0;
text-align: center;
font-size: 8pt;
color: #bbb;
}
/* ============ SECTIONS ============ */
.section { margin-bottom: 28px; page-break-inside: avoid; }
.section-title {
font-size: 12pt;
font-weight: 700;
color: #cc0000;
letter-spacing: -0.01em;
margin-bottom: 48px;
padding-bottom: 6px;
border-bottom: 2px solid #cc0000;
display: flex;
align-items: center;
gap: 8px;
}
.section-title .num {
background: #cc0000;
color: #fff;
width: 26px;
height: 26px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 10pt;
font-weight: 800;
flex-shrink: 0;
}
.section-desc {
font-size: 9.5pt;
color: #555;
margin-bottom: 14px;
}
/* ============ SCORE TABLE ============ */
.score-table {
width: 100%;
border-collapse: collapse;
margin: 12px 0;
}
.score-table th {
text-align: left;
font-size: 9pt;
font-weight: 700;
color: #666;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 8px 12px;
border-bottom: 2px solid #e5e5e5;
background: #fafafa;
}
.score-table td {
padding: 9px 12px;
border-bottom: 1px solid #f0f0f0;
font-size: 9.5pt;
}
.score-table .dim { font-weight: 600; }
.score-bar {
display: inline-block;
height: 10px;
border-radius: 5px;
margin-right: 8px;
vertical-align: middle;
}
.score-critical { background: #cc0000; }
.score-warning { background: #ea580c; }
.score-ok { background: #f59e0b; }
.score-good { background: #16a34a; }
.score-na { background: #d4d4d4; }
/* ============ FATAL FLAWS ============ */
.flaw-box {
background: #fef2f2;
border-left: 4px solid #cc0000;
padding: 12px 16px;
margin: 8px 0;
border-radius: 0 6px 6px 0;
}
.flaw-box .flaw-num {
font-weight: 800;
color: #cc0000;
font-size: 9pt;
margin-right: 6px;
}
.flaw-box .flaw-label {
display: inline-block;
font-size: 7pt;
font-weight: 700;
text-transform: uppercase;
padding: 2px 6px;
border-radius: 3px;
margin-left: 6px;
vertical-align: middle;
}
.flaw-existential { background: #cc0000; color: #fff; }
.flaw-structural { background: #ea580c; color: #fff; }
.flaw-financial { background: #f59e0b; color: #fff; }
.flaw-operational { background: #6366f1; color: #fff; }
/* ============ JUDGE PANEL ============ */
.judge-grid {
display: flex;
gap: 12px;
margin: 12px 0;
}
.judge-card {
flex: 1;
border: 1px solid #e5e5e5;
border-radius: 8px;
padding: 14px;
}
.judge-card .judge-name {
font-weight: 700;
font-size: 10pt;
margin-bottom: 4px;
}
.judge-card .judge-label {
font-size: 8pt;
color: #999;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.judge-card .judge-verdict {
font-weight: 800;
font-size: 11pt;
padding: 4px 0;
}
.judge-verdict .upheld { color: #16a34a; }
.judge-verdict .overruled { color: #cc0000; }
.judge-confidence {
font-size: 8pt;
color: #999;
display: block;
}
.judge-note {
font-size: 8.5pt;
color: #555;
margin-top: 6px;
line-height: 1.4;
}
/* ============ ACTION PLAN ============ */
.action-table {
width: 100%;
border-collapse: collapse;
margin: 12px 0;
}
.action-table th {
text-align: left;
font-size: 9pt;
font-weight: 700;
color: #666;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 8px 12px;
border-bottom: 2px solid #e5e5e5;
}
.action-table td {
padding: 10px 12px;
border-bottom: 1px solid #f0f0f0;
font-size: 9.5pt;
vertical-align: top;
}
.action-table .priority {
font-weight: 800;
width: 60px;
text-align: center;
}
.priority-p0 { color: #cc0000; }
.priority-p1 { color: #ea580c; }
.priority-p2 { color: #f59e0b; }
/* ============ STRENGTHS ============ */
.strength-list { list-style: none; padding: 0; }
.strength-list li {
padding: 6px 0;
padding-left: 20px;
position: relative;
font-size: 9.5pt;
border-bottom: 1px solid #f5f5f5;
}
.strength-list li::before {
content: "\2713";
position: absolute;
left: 0;
color: #16a34a;
font-weight: 800;
}
/* ============ RESEARCH ============ */
.finding {
padding: 8px 0;
border-bottom: 1px solid #f5f5f5;
}
.finding .finding-label {
font-weight: 700;
font-size: 9pt;
color: #555;
text-transform: uppercase;
letter-spacing: 0.03em;
margin-bottom: 2px;
}
.finding .finding-text {
font-size: 9.5pt;
color: #333;
}
.finding .finding-source {
font-size: 7.5pt;
color: #999;
margin-top: 2px;
}
/* ============ COMPARISON TABLE ============ */
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 12px 0;
font-size: 9pt;
}
.comparison-table th {
text-align: left;
padding: 8px 10px;
border-bottom: 2px solid #e5e5e5;
font-weight: 700;
color: #666;
text-transform: uppercase;
letter-spacing: 0.04em;
font-size: 8pt;
}
.comparison-table td {
padding: 8px 10px;
border-bottom: 1px solid #f0f0f0;
}
.comparison-table tr:nth-child(even) td { background: #fafafa; }
.comparison-table .winner { font-weight: 700; color: #16a34a; }
/* ============ FOOTER ============ */
.report-footer {
margin-top: 40px;
padding-top: 16px;
border-top: 1px solid #e5e5e5;
text-align: center;
font-size: 8pt;
color: #999;
}
/* ============ CITATIONS ============ */
.citation {
font-size: 8pt;
color: #777;
padding: 3px 0;
}
.citation a { color: #2563eb; text-decoration: none; }
/* ============ PRINT HELPERS ============ */
.page-break { page-break-before: always; }
.avoid-break { page-break-inside: avoid; }
</style>
</head>
<body>
<!-- ═══════════════════════════════════════════ -->
<!-- COVER PAGE -->
<!-- ═══════════════════════════════════════════ -->
<div class="cover">
<span class="logo">⚖️</span>
<h1>VerdictTank Report</h1>
<p class="subtitle">AI-Powered Proposal Review - Research, Critique, Verdict</p>
<div class="verdict-badge verdict-cond-go">NO-GO - CONDITIONAL GO</div>
<div class="meta">
<strong>Proposal:</strong> {{PROPOSAL_NAME}}<br>
<strong>Submitted by:</strong> {{SUBMITTER_NAME}}<br>
<strong>Date:</strong> {{REVIEW_DATE}}<br>
<strong>Review ID:</strong> {{REVIEW_ID}}
</div>
<div class="cover-footer">
Confidential - Prepared for {{SUBMITTER_NAME}} only<br>
VerdictTank - a product of IT Pro Partner
</div>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- EXECUTIVE SUMMARY -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">1</span> Executive Summary</div>
<p class="section-desc"></p>
<p>{{EXECUTIVE_SUMMARY}}</p>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- RESEARCH FINDINGS -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">2</span> Research Findings</div>
<p class="section-desc">Claims verified against live web data, market databases, and public records.</p>
{{RESEARCH_FINDINGS}}
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- DIMENSION SCORES -->
<!-- ═══════════════════════════════════════════ -->
<div class="section">
<div class="section-title"><span class="num">3</span> Dimension Scores</div>
<p class="section-desc">Scored across 10 dimensions on a 1-10 scale.</p>
<table class="score-table">
<tr><th>Dimension</th><th>Score</th><th>Assessment</th></tr>
{{SCORE_ROWS}}
</table>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- FATAL FLAWS -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">4</span> Fatal Flaws</div>
<p class="section-desc">Issues that must be resolved before proceeding. These are not negotiable.</p>
{{FATAL_FLAWS}}
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- JUDGE PANEL -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">5</span> Judge Panel - Majority Verdict</div>
<p class="section-desc">Three independent judges cross-checked the findings. Each judge operates on fundamentally different architecture for true cross-validation. Majority verdict rules.</p>
<div class="judge-grid">
{{JUDGE_CARDS}}
</div>
<p style="font-size:9.5pt;color:#333;margin-top:12px;">
<strong>Overall:</strong> {{JUDGE_MAJORITY_VERDICT}} ({{JUDGE_AGREEMENT}}/{{JUDGE_TOTAL}} judges agree)
</p>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- STRENGTHS -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">6</span> Strengths</div>
<p class="section-desc">What the proposal gets right. These are the pillars to build on.</p>
<ul class="strength-list">
{{STRENGTHS}}
</ul>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- COMPETITIVE LANDSCAPE -->
<!-- ═══════════════════════════════════════════ -->
<div class="section">
<div class="section-title"><span class="num">7</span> Competitive Landscape</div>
<p class="section-desc">How the proposal stacks up against known competitors and alternatives.</p>
<table class="comparison-table">
<tr><th>Competitor</th><th>Strengths</th><th>Gaps</th><th>Threat Level</th></tr>
{{COMPETITOR_ROWS}}
</table>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- PRIORITY-RANKED ACTION PLAN -->
<!-- ═══════════════════════════════════════════ -->
<div class="section">
<div class="section-title"><span class="num">8</span> Priority-Ranked Action Plan</div>
<p class="section-desc">Actions ordered by urgency. P0 items are blocking - resolve before any P1 work.</p>
<table class="action-table">
<tr><th>Priority</th><th>Action</th><th>Why</th><th>Effort</th></tr>
{{ACTION_ROWS}}
</table>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- JUDGE NOTES -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">9</span> Judge Notes</div>
<p class="section-desc">Individual judge commentary and observations.</p>
{{JUDGE_NOTES}}
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- DISCLAIMER -->
<!-- ═══════════════════════════════════════════ -->
<div class="section avoid-break">
<div class="section-title"><span class="num">10</span> Disclaimer</div>
<p class="section-desc">Important information about this report and its limitations.</p>
<div style="font-size: 8.5pt; color: #666; line-height: 1.6;">
<p><strong>AI-Generated Analysis.</strong> This report was produced by VerdictTank, an AI-powered proposal review platform. All analysis, scores, and recommendations are generated by artificial intelligence and <strong>do not constitute professional business, legal, financial, or investment advice.</strong></p>
<p><strong>For Informational Purposes Only.</strong> The content of this report is provided for informational and educational purposes only. It is not a substitute for consultation with qualified business advisors, attorneys, accountants, or other licensed professionals. You should consult with appropriate professionals before making business decisions based on any information contained in this report.</p>
<p><strong>No Guarantee of Results.</strong> VerdictTank and IT Pro Partner make no representations or warranties regarding the accuracy, completeness, or reliability of the analysis. Past performance of the AI review methodology does not guarantee future results. The scores and verdicts reflect algorithmic assessment at a point in time and should not be treated as predictions of business success or failure.</p>
<p><strong>No Liability.</strong> To the fullest extent permitted by law, IT Pro Partner, its owners, employees, and affiliates disclaim all liability for any direct, indirect, incidental, or consequential damages arising from your use of or reliance on this report, including but not limited to lost profits, business interruption, or missed opportunities.</p>
<p><strong>Data and Privacy.</strong> Your proposal content is treated as confidential. Proposals are processed through the VerdictTank AI pipeline and are not retained beyond what is necessary to produce this report, unless you explicitly opt into data retention. See our full Privacy Policy at <strong>verdicttank.com/privacy</strong>.</p>
<p><strong>Third-Party Data.</strong> Competitive research in this report may include data from third-party sources. VerdictTank does not independently verify third-party data and makes no warranty as to its accuracy.</p>
<p><strong>Acceptance.</strong> By reviewing this report, you acknowledge that you have read and understood this disclaimer and agree to its terms.</p>
</div>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- CITATIONS -->
<!-- ═══════════════════════════════════════════ -->
<div class="section">
<div class="section-title"><span class="num">11</span> Citations &amp; Sources</div>
<p class="section-desc"></p>
{{CITATIONS}}
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- FOOTER -->
<!-- ═══════════════════════════════════════════ -->
<div class="report-footer">
<strong>VerdictTank</strong> - a product of <strong>IT Pro Partner</strong><br>
This report is confidential and intended solely for {{SUBMITTER_NAME}}.<br>
Generated {{REVIEW_DATE}} - Review ID: {{REVIEW_ID}}
</div>
</body>
</html>
+75
View File
@@ -0,0 +1,75 @@
{
"proposal_name": "Practice Axis - Orthodontic Consulting Platform",
"submitter_name": "Anita Brown",
"review_date": "August 7, 2026",
"review_id": "VT-20260807-PA001",
"executive_summary": "Practice Axis is a solo orthodontic consulting firm built around two proprietary tools: a Schedule Builder and a Feasibility Tool. The concept targets orthodontists considering private practice, offering a data-driven alternative to traditional consulting. While the founder brings direct clinical operations experience and the tools address a real pain point, five fatal flaws were identified that prevent a GO verdict: zero market validation, no paid pilot, brand confusion with orthodontic treatment coordinators, missing competitive differentiation, and a tool-only positioning that undersells the consulting value. The majority verdict is NO-GO converting to CONDITIONAL GO once the five flaws are addressed. This is not a rejection - it is a structured path to a fundable proposal.",
"scores": [
{"name": "Market Validation", "score": 2, "note": "Zero customer interviews, no waitlist, no paid pilot. Market demand is entirely assumed."},
{"name": "Founder-Market Fit", "score": 6, "note": "Hands-on orthodontic operations experience at Wall Orthodontics. Knows the day-to-day but has not consulted independently."},
{"name": "Business Model", "score": 5, "note": "Consulting-based model is viable but pricing is undefined. Revenue projections lack underlying assumptions."},
{"name": "Competitive Moat", "score": 3, "note": "Tools are the differentiator but no IP protection, no technical barrier, no network effects identified."},
{"name": "Go-to-Market", "score": 4, "note": "No channel strategy beyond personal network. No content plan, no partnership strategy, no ad budget."},
{"name": "Technical Feasibility", "score": 8, "note": "Schedule Builder and Feasibility Tool are straightforward web applications. Well within build capabilities."},
{"name": "Unit Economics", "score": 4, "note": "No cost structure, no CAC estimate, no LTV model. Consulting margins are assumed, not calculated."},
{"name": "Team & Execution", "score": 5, "note": "Solo founder with strong operations background but no sales, marketing, or tech co-founder."},
{"name": "Regulatory Risk", "score": 7, "note": "Consulting does not require licensure. Feasibility assessments are advisory, not legal opinions."},
{"name": "Scalability", "score": 3, "note": "1:1 consulting model caps revenue at founder's time. No productized tier, no group program, no platform pivot."}
],
"fatal_flaws": [
{"title": "Zero Market Validation", "severity": "Existential", "detail": "No orthodontists have been interviewed, surveyed, or recruited for a paid pilot. The entire proposal rests on assumed demand. Without at least 5-10 validated conversations confirming willingness to pay, the proposal cannot move forward. This is the single most critical gap."},
{"title": "No Paid Pilot or Waitlist", "severity": "Existential", "detail": "A CONDITIONAL GO requires either one paid pilot engagement at any price point or a documented waitlist of 10+ qualified prospects. Currently neither exists. The pilot does not need to be profitable - it needs to prove someone will pay."},
{"title": "Brand Confusion - Treatment Coordinator Overlap", "severity": "Brand-fatal", "detail": "In orthodontic practices, a Treatment Coordinator (TC) is a specific clinical-sales role that presents treatment plans and closes cases. 'Schedule Builder' sounds adjacent to TC duties. Orthodontists will hear 'another TC tool' rather than 'strategic consulting.' The name and positioning must be rebuilt from scratch."},
{"title": "Missing Competitive Differentiation", "severity": "Structural", "detail": "The proposal does not acknowledge or differentiate from Levin Group, OrthoFi, Gaidge, or Dental Nachos. Several of these offer practice analytics. The Feasibility Tool's unique angle is unclear against incumbent platforms that orthodontists already use."},
{"title": "Tool-Only Positioning Undersells Value", "severity": "Structural", "detail": "The proposal leads with software tools rather than consulting outcomes. The value is in Anita's judgment and experience - the tools should be positioned as deliverables of that expertise, not the product itself. 'I help orthodontists open practices that cash-flow in 90 days' is categorically different from 'I built a Schedule Builder.'"}
],
"judges": [
{"name": "Judge 1", "verdict": "upheld", "confidence": "High", "note": "Agrees with all five fatal flaws. Particularly concerned about brand confusion - the Treatment Coordinator overlap is not cosmetic, it is a positioning liability. The tools have merit but the framing must change before this can go to market."},
{"name": "Judge 2", "verdict": "upheld", "confidence": "High", "note": "Upheld with emphasis on the competitive landscape gap. Levin Group dominates this space with 30+ years of brand equity. Practice Axis must define its wedge clearly. Recommends the competitive research be done before the pilot so the pilot validates differentiation, not just demand."},
{"name": "Judge 3", "verdict": "upheld", "confidence": "Medium", "note": "Review completed on initial findings and scores. No dissent registered against the majority position. All five fatal flaws are substantiated by the research record."}
],
"judge_majority_verdict": "NO-GO converting to CONDITIONAL GO - 5 fatal flaws must be resolved",
"judge_agreement": 3,
"strengths": [
"Direct clinical operations experience - Anita knows the orthodontic workflow from inside a practice, not from management consulting textbooks",
"Proprietary tools (Schedule Builder + Feasibility Tool) create a tangible deliverable that generic consultants cannot offer",
"Clear target persona (orthodontists considering private practice) is well-defined and reachable through professional associations",
"Hybrid consulting + software model commands higher rates than pure consulting and creates recurring engagement opportunities",
"Low capital requirements - no office, no staff, no inventory needed to launch",
"Regulatory landscape is favorable - consulting does not require licensure and feasibility assessments are advisory"
],
"competitors": [
{"name": "Levin Group", "strengths": "30+ year brand, 30k+ clients, comprehensive practice management", "gaps": "General dental focus, not ortho-specific. Expensive retainers.", "threat": "High"},
{"name": "OrthoFi", "strengths": "Patient financing + practice analytics platform", "gaps": "Software-first, not consulting. Focused on existing practices.", "threat": "Medium"},
{"name": "Gaidge", "strengths": "Ortho-specific analytics with benchmarking", "gaps": "Data platform, not a launch consultancy. Requires existing practice data.", "threat": "Medium"},
{"name": "Dental Nachos", "strengths": "Community + courses for new dentists", "gaps": "General dentistry, course-based model. No 1:1 consulting.", "threat": "Low"},
{"name": "McKenzie & Company", "strengths": "Gold-standard consulting brand, deep healthcare practice", "gaps": "Not ortho-specific. Six-figure engagements. Wrong customer segment.", "threat": "Low"}
],
"action_plan": [
{"priority": "0", "action": "Conduct 10 structured orthodontist interviews", "why": "Validates (or invalidates) core assumptions before any further investment", "effort": "2-3 weeks"},
{"priority": "0", "action": "Land one paid pilot engagement at any price", "why": "Proves willingness to pay - the single most important signal to investors and yourself", "effort": "4-6 weeks"},
{"priority": "0", "action": "Rebuild brand and naming from scratch", "why": "Current name overlaps with Treatment Coordinator role - fatal positioning error", "effort": "1-2 weeks"},
{"priority": "1", "action": "Complete competitive audit with differentiation wedge", "why": "Must define what Practice Axis does that Levin/OrthoFi/Gaidge cannot replicate", "effort": "2 weeks"},
{"priority": "1", "action": "Reposition as consulting outcomes with tools as deliverables", "why": "Current framing leads with software - value is Anita's judgment, tools are proof of process", "effort": "1 week"},
{"priority": "2", "action": "Define 3-tier pricing model with entry point under $2,500", "why": "Creates accessible on-ramp while preserving premium consulting tier", "effort": "1 week"},
{"priority": "2", "action": "Build content strategy targeting AAO conference cycle", "why": "Orthodontists cluster at AAO - the annual meeting is the highest-density lead generation event", "effort": "Ongoing"}
],
"research": [
{"label": "Market Size", "text": "Approximately 7,500 orthodontic practices in the United States. Roughly 200-300 new practices open annually. Consulting market for dental/ortho startups estimated at $50-80M annually.", "source": "ADA Health Policy Institute, AAO member data"},
{"label": "Treatment Coordinator Role", "text": "Treatment Coordinator (TC) is an established clinical-sales role in orthodontic practices. TCs present treatment plans, handle financial arrangements, and close cases. Naming a consulting tool 'Schedule Builder' creates immediate cognitive overlap with TC scheduling duties.", "source": "Orthodontic practice job boards, AAO career resources"},
{"label": "Levin Group Dominance", "text": "Levin Group has trained over 30,000 dental professionals across 40+ years. Their orthodontic consulting arm is the default option for most practices considering expansion. They offer practice analysis tools that partially overlap with the Feasibility Tool concept.", "source": "Levin Group public materials, Dental Economics features"},
{"label": "Competing Analytics Platforms", "text": "Gaidge provides ortho-specific practice analytics with benchmarking against peer practices. OrthoFi combines patient financing with practice performance dashboards. Both require an existing practice - neither serves the pre-launch feasibility market.", "source": "Gaidge.com, OrthoFi.com product pages"},
{"label": "AAO Annual Session", "text": "The American Association of Orthodontists Annual Session draws 15,000+ attendees. This is the highest-density target audience event. A launch timed with AAO and a booth/content strategy there would be the single most efficient GTM motion.", "source": "AAO.org, past Annual Session attendance data"},
{"label": "Solo Consulting Economics", "text": "Solo strategy consultants in healthcare typically charge $150-400/hr or $2,500-15,000 per engagement. At 60% utilization, a solo consultant billing $200/hr grosses approximately $250K annually. Productized tools can add $50-100K in recurring software revenue.", "source": "Industry benchmarks, consulting rate surveys"},
{"label": "Practice Launch Timeline", "text": "The average orthodontic practice launch timeline from lease signing to first patient is 9-14 months. The highest-risk period is months 2-6 (buildout + credentialing) when no revenue is coming in. A Feasibility Tool that models this cash-flow gap would address the specific anxiety of every new practice owner.", "source": "Orthodontic practice management literature, dental lender guidelines"}
],
"citations": [
{"text": "ADA Health Policy Institute - Dental Practice Statistics", "url": "https://www.ada.org/resources/research/health-policy-institute"},
{"text": "American Association of Orthodontists - Membership and Annual Session Data", "url": "https://www.aaoinfo.org/"},
{"text": "Levin Group - Orthodontic Practice Consulting", "url": "https://www.levingroup.com/orthodontics"},
{"text": "Gaidge - Orthodontic Analytics Platform", "url": "https://www.gaidge.com/"},
{"text": "OrthoFi - Patient Financing and Practice Analytics", "url": "https://www.orthofi.com/"},
{"text": "Dental Economics - Orthodontic Practice Management Articles", "url": "https://www.dentaleconomics.com/"},
{"text": "Industry Benchmark: Healthcare Consulting Rates 2025-2026", "url": "https://www.consulting.com/healthcare-consulting-rates"}
]
}