Spaces:
Sleeping
Sleeping
docs: rule on the Task 1 provenance gap
Browse filesholdings gains retrieved_at: as_of is the position date printed in the fund's
report, not the date we read it, so nothing distinguished a holding scraped
this morning from one scraped months ago. signals gain nothing — observed_at
and url already are the retrieval timestamp and the source. Spec prose amended
to name the actual per-table fields instead of contradicting its own model.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XzekHxqiXutBW4gw3Arsx
docs/superpowers/plans/2026-08-29-prospection-buyside.md
CHANGED
|
@@ -223,6 +223,7 @@ CREATE TABLE IF NOT EXISTS holdings (
|
|
| 223 |
as_of TEXT,
|
| 224 |
source_url TEXT NOT NULL,
|
| 225 |
confidence TEXT NOT NULL,
|
|
|
|
| 226 |
confirmed_at TEXT,
|
| 227 |
UNIQUE (account_id, fund_name, raw_label)
|
| 228 |
);
|
|
@@ -397,9 +398,10 @@ def active_signals(account_id: int, today: date) -> list[dict]:
|
|
| 397 |
|
| 398 |
def upsert_holding(row: dict) -> int:
|
| 399 |
cols = ["account_id", "fund_name", "raw_label", "ticker", "weight_pct",
|
| 400 |
-
"as_of", "source_url", "confidence"]
|
| 401 |
updates = ", ".join(f"{c}=excluded.{c}" for c in ["ticker", "weight_pct", "as_of",
|
| 402 |
-
"source_url", "confidence"
|
|
|
|
| 403 |
with connect() as conn:
|
| 404 |
conn.execute(
|
| 405 |
f"INSERT INTO holdings ({', '.join(cols)}) VALUES ({', '.join('?' * len(cols))}) "
|
|
@@ -2362,6 +2364,7 @@ validateur de rédaction ne voit jamais une ligne non confirmée.
|
|
| 2362 |
from __future__ import annotations
|
| 2363 |
|
| 2364 |
import re
|
|
|
|
| 2365 |
from pathlib import Path
|
| 2366 |
|
| 2367 |
from prospection.sources.ticker_aliases import ALIASES
|
|
@@ -2415,6 +2418,7 @@ def extract_holdings(pdf_path: Path, source_url: str) -> list[dict]:
|
|
| 2415 |
"as_of": None,
|
| 2416 |
"source_url": source_url,
|
| 2417 |
"confidence": "probable",
|
|
|
|
| 2418 |
"confirmed_at": None,
|
| 2419 |
})
|
| 2420 |
return rows
|
|
|
|
| 223 |
as_of TEXT,
|
| 224 |
source_url TEXT NOT NULL,
|
| 225 |
confidence TEXT NOT NULL,
|
| 226 |
+
retrieved_at TEXT NOT NULL,
|
| 227 |
confirmed_at TEXT,
|
| 228 |
UNIQUE (account_id, fund_name, raw_label)
|
| 229 |
);
|
|
|
|
| 398 |
|
| 399 |
def upsert_holding(row: dict) -> int:
|
| 400 |
cols = ["account_id", "fund_name", "raw_label", "ticker", "weight_pct",
|
| 401 |
+
"as_of", "source_url", "confidence", "retrieved_at"]
|
| 402 |
updates = ", ".join(f"{c}=excluded.{c}" for c in ["ticker", "weight_pct", "as_of",
|
| 403 |
+
"source_url", "confidence",
|
| 404 |
+
"retrieved_at"])
|
| 405 |
with connect() as conn:
|
| 406 |
conn.execute(
|
| 407 |
f"INSERT INTO holdings ({', '.join(cols)}) VALUES ({', '.join('?' * len(cols))}) "
|
|
|
|
| 2364 |
from __future__ import annotations
|
| 2365 |
|
| 2366 |
import re
|
| 2367 |
+
from datetime import datetime
|
| 2368 |
from pathlib import Path
|
| 2369 |
|
| 2370 |
from prospection.sources.ticker_aliases import ALIASES
|
|
|
|
| 2418 |
"as_of": None,
|
| 2419 |
"source_url": source_url,
|
| 2420 |
"confidence": "probable",
|
| 2421 |
+
"retrieved_at": datetime.utcnow().isoformat(timespec="seconds"),
|
| 2422 |
"confirmed_at": None,
|
| 2423 |
})
|
| 2424 |
return rows
|
docs/superpowers/specs/2026-08-29-prospection-buyside-design.md
CHANGED
|
@@ -19,8 +19,10 @@ d'implémentation.
|
|
| 19 |
|
| 20 |
**Le dossier prospection applique le même contrat d'évidence que le produit.**
|
| 21 |
|
| 22 |
-
Chaque ligne de contact, de position et de signal porte
|
| 23 |
-
|
|
|
|
|
|
|
| 24 |
personnalisation n'entre dans un email si elle n'est pas adossée à une ligne
|
| 25 |
stockée portant une URL source. Un cold email qui invente une position détruit
|
| 26 |
la crédibilité auprès d'un acheteur régulé — et c'est aussi l'exigence RGPD de
|
|
|
|
| 19 |
|
| 20 |
**Le dossier prospection applique le même contrat d'évidence que le produit.**
|
| 21 |
|
| 22 |
+
Chaque ligne de contact, de position et de signal porte sa provenance et sa
|
| 23 |
+
date de collecte : `source` / `confidence` / `retrieved_at` pour un contact,
|
| 24 |
+
`source_url` / `confidence` / `retrieved_at` pour une position, `url` /
|
| 25 |
+
`weight` / `observed_at` pour un signal. La rédaction est *fail-closed* : aucune affirmation de
|
| 26 |
personnalisation n'entre dans un email si elle n'est pas adossée à une ligne
|
| 27 |
stockée portant une URL source. Un cold email qui invente une position détruit
|
| 28 |
la crédibilité auprès d'un acheteur régulé — et c'est aussi l'exigence RGPD de
|