Add concrete IPO stage dates to reports

Request:
- Include the concrete T0, T1, T2, and D1 dates in every analyst report.

Changes:
- Add a Stage Calendar section to the single-IPO report generator.
- Require analyst reports to include ticker-specific T0 subscription window, T1 allotment-result date, T2 grey-market date/window, and D1 listing date.
- Update the 06106 T0 report with its concrete stage dates.
- Document the requirement in the analyst skill, README, and rule change log.

Verification:
- Ran py_compile for scripts/generate_ipo_report.py.
- Generated a 06106 dry-run report and checked the stage calendar.
- Ran git diff --check.

Next useful context:
- For 06106, T0 is 2026-06-15 to 2026-06-18, T1/T2 is 2026-06-23, and D1 is 2026-06-24.
This commit is contained in:
2026-06-15 14:24:06 +00:00
parent 29ed22e476
commit 07d7a0064a
5 changed files with 78 additions and 1 deletions
+44
View File
@@ -287,6 +287,46 @@ def facts_table(record: dict[str, str], stage: str) -> str:
return "\n".join(lines)
def stage_calendar_table(record: dict[str, str]) -> str:
application_start = fmt_value(record["application_start_date"])
application_end = fmt_value(record["application_end_date"])
allotment_date = fmt_value(record["allotment_results_expected_date"])
listing_date = fmt_value(record["listing_date"])
if allotment_date != "n/a":
t2_date = f"{allotment_date} after allotment results"
elif listing_date != "n/a":
t2_date = "trading day before D1; exact date not archived"
else:
t2_date = "n/a"
rows = [
(
"T0_prospectus",
f"{application_start} to {application_end}",
"Subscription window; use prospectus and offer terms only.",
),
(
"T1_allotment",
allotment_date,
"Allotment results day; use public demand, placing demand, and allocation facts.",
),
(
"T2_grey_market",
t2_date,
"Pre-listing grey-market sell window if a reliable executable source exists.",
),
(
"D1",
listing_date,
"First official trading day; default sell window when T2 data is unavailable or unreliable.",
),
]
lines = ["| Stage | Concrete Date For This IPO | Meaning |", "| --- | --- | --- |"]
for stage, date_text, meaning in rows:
lines.append(f"| `{stage}` | {date_text} | {meaning} |")
return "\n".join(lines)
def source_paths(record: dict[str, str], stage: str) -> list[str]:
paths = []
if record["prospectus_source_path"]:
@@ -367,6 +407,10 @@ def build_report(record: dict[str, str], rows: list[dict[str, str]], stage: str,
f"- Score bucket: `{bucket}`",
f"- Calibrated D1 positive probability: {fmt_pct_rate(metric.d1_positive_rate)} from {metric.sample_size} historical D1 labels",
"",
"## Stage Calendar",
"",
stage_calendar_table(record),
"",
"## Facts",
"",
facts_table(record, stage),