Funzioni comuni
Primitive trasversali condivise da ogni dominio — il profilo aziendale/di dominio configurabile, la classificazione deterministica della sensibilità, il glossario delle dimensioni, l'osservabilità rispettosa della privacy e le costanti di percorso globali.
Il dominio common contiene le primitive trasversali da cui dipendono tutti gli altri domini: il profilo aziendale/di dominio configurabile (così nessuna azienda è mai codificata in modo fisso), il modello deterministico di sensibilità, il glossario delle dimensioni, l'osservabilità rispettosa della privacy e l'unica fonte di verità per i percorsi globali. Queste primitive non hanno dipendenze dal resto del sistema — sono la base del grafo di import.
Pacchetto: src/ragspine/common/. Contratto: src/ragspine/common/CLAUDE.md.
Struttura
Profilo aziendale / di dominio
company_profile.py rende RAGSpine un copilota gestionale generico anziché un'applicazione
finanziaria codificata in modo fisso. Identità, sinonimi, dimensioni e l'elenco dei concorrenti provengono tutti da un file TOML
(config/company.toml); in assenza del file si ricade silenziosamente sui valori predefiniti ACME integrati.
Il profilo è una frozen dataclass immutabile. CompanyProfile è un alias a livello di modulo
per la stessa classe DomainProfile — entrambi i nomi funzionano nei controlli isinstance e nei costruttori.
Proprietà
Tipo
Ogni dimensione dichiarata è un DimensionSpec immutabile (ADR 0004): name, label, kind
(categorical / temporal / measure), synonyms, units, labels, default,
required, clarify (ask_first / assume / none), identity, expand,
derived_from / derivation, e i flag della whitelist di prevenzione delle risposte inventate. Il profilo predefinito
dichiara cinque dimensioni — metric, entity, period (temporale), channel
(predefinito TOTAL, non espandibile) e geography (identity=False, derivato da entity).
from ragspine.common.company_profile import load_company_profile
profile = load_company_profile() # explicit path > $RAGSPINE_COMPANY_CONFIG > config/company.toml
print(profile.home_entity_code) # 'ACME_GROUP' by defaultload_company_profile(path=None) risolve il percorso di configurazione (argomento esplicito →
variabile d'ambiente RAGSPINE_COMPANY_CONFIG → config/company.toml), lo analizza con tomllib/tomli,
e ricade sul valore predefinito integrato in caso di file mancante o non analizzabile — senza mai sollevare eccezioni,
senza mai stampare nulla.
Guidato dalla configurazione, nessuna azienda codificata in modo fisso. Identità, metriche e concorrenti provengono dal profilo.
La mappa external_entities (alias concorrente → nome visualizzato) è il modo in cui l'agente riconosce una
domanda su un concorrente fuori ambito. Non codificare in modo fisso un'azienda da nessuna parte.
Sensibilità
sensitivity.py è il livello deterministico di classificazione dei dati applicato dal percorso di
ingestione narrativa e da cui dipende a valle
l'isolamento RESTRICTED. I livelli sono
semplici stringhe — non esiste alcun enum. L'unica costante con nome è RESTRICTED = "RESTRICTED";
il valore predefinito per i contenuti non contrassegnati è "INTERNAL".
Le regole risiedono in un SensitivityPolicy immutabile (letto dalla sezione di configurazione [sensitivity],
nessuna parola aziendale codificata in modo fisso):
Proprietà
Tipo
classify_sensitivity(filename, text, policy) -> str è una funzione pura (zero chiamate
esterne) che restituisce il primo livello corrispondente, in ordine di priorità:
restricted_filename_patterns → RESTRICTEDrestricted_keywords → RESTRICTEDescalate_unknown_to_restricted è True → RESTRICTEDpolicy.default_level (predefinito "INTERNAL")La postura di sicurezza: i documenti non contrassegnati hanno come valore predefinito INTERNAL; il rilevamento di un segnale eleva a
RESTRICTED; il comportamento generalizzato "tutto ciò che è sconosciuto → RESTRICTED" è un interruttore rigoroso
opt-in, disattivato per impostazione predefinita.
Glossario
glossary.py normalizza i sinonimi delle dimensioni in forma libera in codici controllati. Non esiste alcuna
classe — si tratta di funzioni a livello di modulo più dizionari derivati dal profilo caricato.
Un input non riconosciuto restituisce None; non tira mai a indovinare.
| funzione | mappa |
|---|---|
normalize_metric(raw) -> str | None | sinonimo di metrica → metric_code |
normalize_entity(raw) -> str | None | sinonimo di entità → entity_code |
resolve_external_entity(text) -> str | None | menzione di concorrente → nome visualizzato (corrispondenza più lunga) |
geography_for_entity(entity_code) -> str | None | area geografica predefinita per un'entità |
unit_for_metric(metric_code) -> str | None | unità predefinita per una metrica |
normalize_period(raw) -> tuple[str, str] | None | periodo assoluto → (period_type, period) |
resolve_relative_period(raw, reference_date=None) -> tuple[str, str] | None | periodo relativo (今年/去年/上季度…) → (period_type, period) |
La normalizzazione dei periodi produce gli stessi valori period_type utilizzati dal
fact store: FY (FY2024 / 2024),
HY (2024H1) e QUARTER (2025Q1).
from ragspine.common.glossary import normalize_metric, normalize_period
normalize_metric("营收") # 'REVENUE'
normalize_period("FY 2024") # ('FY', '2024')
normalize_metric("not a metric") # None — never guessesOsservabilità
observability.py consiste in due piccole primitive:
new_request_id() -> str— un codice breve esadecimaleuuid4di 12 caratteri.emit_trace(logger=None, **fields) -> None— registra un record INFO con il messaggio fisso"trace", allegando**fieldsal record di log tramiteextra=. Usa esclusivamente la libreria standardlogging(nessunbasicConfig); l'host o il test si occupa di collegare l'handler. Il nome del logger èTRACE_LOGGER_NAME = "ragspine.trace".
Trace rispettosi della privacy. I log sono trattati come Restricted. emit_trace è pensato per trasportare solo
metadati non sensibili — request_id, route, codici controllati (metrica / entità / periodo / canale),
conteggi di stato, punteggi, flag booleani, durate, utilizzo di token — e mai il testo grezzo della risposta,
il valore di un fatto o il testo di un chunk.
Core — costanti globali
core.py è l'unica fonte di verità per i percorsi, derivati da __file__ (nessuna dipendenza dalla cwd o da
rootutils, zero effetti collaterali al momento dell'import):
| costante | valore |
|---|---|
REPO_ROOT | radice del repository, da Path(__file__).parents[3] |
DATA_DIR | REPO_ROOT / "data" |
DEFAULT_FACT_DB | data/fact_metric.db — tabella dei fatti e tabella dei chunk narrativi (stesso sqlite) |
DEFAULT_MAPPING_DB | data/color_mapping.db — registro di mappatura dei colori |
DEFAULT_REVIEW_QUEUE_DB | data/review_queue.db — coda di revisione SME |
Invarianti garantiti da questo dominio
- Guidato dalla configurazione — identità / metriche / concorrenti provengono da
CompanyProfile; non codificare mai in modo fisso un'azienda. - Trace rispettosi della privacy —
observabilityregistra solo codici / conteggi / tempi, mai la risposta, il valore di un fatto o il testo di un chunk. - Normalizzazione deterministica, senza mai tirare a indovinare — il glossario e il classificatore di sensibilità sono
funzioni pure; un input non riconosciuto restituisce
None/ il livello predefinito.
Correlati
Pipeline
Esportazione del PipelineGraph statico del motore e in cosa differisce dal protocollo v1 di anteprima del flusso di lavoro a sola visualizzazione.
Configurazione
Variabili d'ambiente di ServiceConfig, selettori di recupero, gate di esecuzione dei flussi di lavoro, credenziali delle API pubbliche e CompanyProfile.