Backfill sparse report sections, add enrichment section refresh, and bootstrap first-admin

Reports: the LLM reliably used company_enrichment for prose fields but
inconsistently populated the parallel Finding-list/string-list fields from
the same evidence, even with progressively more explicit prompting. Add a
code-level backfill (products, recent developments, financial signals,
strategic initiatives, regulatory signals, risks/opportunities mirrored
from SWOT, unknowns, monitoring recommendations) that only ever fills in
what the model left empty, never overwrites what it produced.

Enrichment tab: reorder sections (Products/Recent updates before
Customers/Competitors) and add a per-section "Refresh" button that
re-fetches just one of NinjaPear's six independent per-company endpoints
when it came back empty - confirmed live that a data-coverage gap (e.g.
Amazon returning no products) is real provider behavior, not a bug.

Auth: the first account registered on a deployment with zero existing
admins is now auto-promoted to admin, closing the chicken-and-egg gap
where the only path to admin access was direct DB access. Self-heals if
the last admin ever deletes their account.

Also bumps nginx's proxy_read_timeout for api.ciagent.org to cover the
enrichment refresh's synchronous funding-endpoint call (up to 5 minutes
per NinjaPear's docs).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-06 17:41:02 -04:00
co-authored by Claude Sonnet 5
parent 1be3e53584
commit 18305b545c
18 changed files with 1087 additions and 53 deletions
+59 -10
View File
@@ -21,17 +21,66 @@ SYSTEM_PROMPT = (
"third-party data provider at onboarding, also real evidence, not your own knowledge), "
"stored source documents, and previously detected changes. Never introduce "
"facts from outside knowledge, even if you recognize the company - if it isn't in the "
"evidence block, it doesn't go in the report. The company_profile and company_enrichment "
"fields ARE real evidence and should ground company_overview/market_positioning/"
"financial_signals/leadership_changes/products_and_services/competitor_comparison/"
"customer_sentiment/etc even when source_documents and detected_changes are sparse or "
"evidence block, it doesn't go in the report.\n\n"
"company_profile and company_enrichment are real evidence and must ground every "
"applicable section even when source_documents and detected_changes are sparse or "
"empty - do not say 'insufficient evidence' for a field company_profile or "
"company_enrichment already answers. Every finding must be "
"traceable to the evidence given and must carry an honest confidence label: confirmed "
"(the source states it directly), strongly_indicated, likely, possible, unconfirmed, or "
"insufficient_evidence. When evidence is thin or missing for a section, say so explicitly "
"in that section rather than inventing content. Distinguish clearly between what a source "
"states and what you are inferring."
"company_enrichment already answers. In particular, the list-of-Finding sections are "
"NOT limited to newly detected changes - they must also represent the company's "
"current, confirmed state whenever company_enrichment/company_profile answers them "
"directly, the same way you would use that evidence for a prose field:\n"
"- products_and_services: if company_enrichment.products is present, emit ONE Finding "
"per product (headline = product name, summary = its description/category, "
"confidence = confirmed). A Finding's evidence array may be empty ([]) - "
"company_enrichment is itself the evidence, and an empty evidence array is valid and "
"expected here since there is no source_document or url to cite for it. For example, "
"given company_enrichment.products containing {\"name\": \"Acme Pay\", \"category\": "
"\"Payments\", \"description\": \"Lets merchants accept cards online.\"}, emit: "
"{\"headline\": \"Acme Pay\", \"summary\": \"Lets merchants accept cards online "
"(Payments).\", \"confidence\": \"confirmed\", \"evidence\": []}. Do not leave "
"products_and_services empty just because no source_document specifically announces a "
"product, and do not skip a product merely because you have nothing to put in its "
"evidence array.\n"
"- recent_developments: if company_enrichment.recent_updates is present, emit ONE "
"Finding per genuinely distinct update (headline paraphrasing its text, date = its "
"date, confidence = confirmed since it is the company's own published content, "
"evidence = [{\"url\": its url, \"description\": \"one sentence\"}]). You may skip "
"near-duplicate or routine items, but do not leave this empty when recent_updates has "
"substantive entries.\n"
"- strategic_initiatives and key_inferred_projects: these are your own synthesis "
"across company_enrichment.recent_updates, products, and description - identify "
"recurring or notable strategic themes (a new market entered, a technology bet, a "
"business-model shift) that no single item states outright. Use a lower confidence "
"label here (likely/possible) since this is inference, not a directly-stated fact - "
"an empty evidence array is fine here too. Do not leave these empty just because "
"nothing states 'this is a strategic initiative' in so many words - if you can name a "
"theme in executive_summary or market_positioning, that same theme belongs here as a "
"Finding/InferredProject too, not only as prose. If market_positioning or "
"company_overview names ANY theme, direction, or bet the company is making, restate it "
"here as at least one Finding/InferredProject before considering this section done.\n"
"- regulatory_and_legal_signals: derive from anything in company_enrichment or "
"source_documents touching licensing, compliance, jurisdictions of operation, or legal "
"structure (e.g. a payments company operating in many countries implies licensing/"
"compliance obligations even if no single document states them). If genuinely nothing "
"in the evidence touches this even indirectly, emit one Finding with confidence "
"insufficient_evidence explaining that rather than an empty list.\n"
"- unknowns_and_missing_data and monitoring_recommendations: these two are NOT findings "
"about the company - they are your own meta-analysis of this report and evidence set, so "
"they almost never have 'insufficient evidence' as a valid reason to be empty. You "
"always have something to say: unknowns_and_missing_data should name specific "
"categories of information this evidence set does NOT cover (e.g. 'no financial "
"statements or revenue figures were available', 'no employee reviews or Glassdoor "
"sentiment data', 'pricing details were not provided'); monitoring_recommendations "
"should name specific things worth watching for on the next run (e.g. 'watch for "
"updates to the products list', 'monitor for new funding rounds', 'track leadership "
"page for executive changes'). Leave these empty ONLY if you truly cannot think of a "
"single gap or follow-up, which should be rare.\n\n"
"Every finding must still be traceable to the evidence given and must carry an honest "
"confidence label: confirmed (the source states it directly), strongly_indicated, "
"likely, possible, unconfirmed, or insufficient_evidence. When evidence is genuinely "
"thin or missing for a section, say so explicitly in that section rather than "
"inventing content. Distinguish clearly between what a source states and what you are "
"inferring."
)