Skip to content

Commit a7ded43

Browse files
committed
추가: 공통 PIT 팩터 계약과 EDGAR 재무 작업대
1 parent 832d5e0 commit a7ded43

36 files changed

Lines changed: 4068 additions & 1124 deletions

mainPlan/unified-data-workbench/04-verification-progress-ledger.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
| W7 | Signature Data Prism 혼합 query, evidence, quality, Arrow | 완료 |
1515
| W8 | 170개 전수 실행, selector, 빈 결과, 동시성 hardening | 완료 |
1616
| W9 | 실제 content 봉인, 외부 구조 보존, 전종목 자동 page 소비 | 완료 |
17+
| W10 | 공통 feature observation 계약과 실제 EDGAR PIT factor 수직 슬라이스 | 완료 |
1718

1819
## 2. unit과 contract test
1920

@@ -189,3 +190,23 @@ uv run python -X utf8 tests/audit/dartlabGuard.py strict --scope l0-l15 --provid
189190
- 한 Python 소비 흐름에서 DART 5개와 EDGAR 4개 synthetic shard를 중복과 누락 없이 완주
190191
- resource owner의 description과 read가 single-use manifest session을 공유해 전수 manifest 순회를 page당 3회에서 2회로 축소
191192
- strict mutable source의 pre-snapshot과 반환 전 post-validation, committed replay 무접촉 계약 유지
193+
194+
### 2026-07-23 W10
195+
196+
- feature registry, observation, vintage, revision-aware query 계약을 `dartlab.data` 공통 계층으로 이동
197+
- 기존 simulator import 경로는 compatibility re-export로 유지해 외부 작업대와 simulator의 의미 규칙 통일
198+
- 엄격한 달력 날짜, `MARKET:ID` entity, feature definition과 normalization 결박, duplicate와 normalization drift 차단
199+
- valid time과 knowledge time, staleness, bounds, same-day date precision, missing matrix, 동일 timestamp revision ambiguity를 공통 PIT selector에서 검증
200+
- `observationPIT` 선언 owner가 typed observation envelope 대신 일반 frame을 반환하면 실행 후 fail-closed
201+
- `analysis.edgarFinancialFeatures` callable asset을 catalog에 추가해 전체 354개, queryable 171개, callable 2개로 확장
202+
- 로컬 EDGAR companyfacts 전용 9열 reader와 operating-company reduced financial feature owner 구현
203+
- 외부 JSON mapping 한 번 호출에서 AAPL revenue와 operating margin을 factor row로 반환하고 actual filing time, observation ID, revision ID, feature version, lineage를 보존
204+
- query cutoff가 달라도 같은 evidence와 값이면 동일 observation과 revision identity를 유지
205+
- retained companyfacts의 과거 admission snapshot 부재를 `latestRetained`, `periodOnly`, `conditional` gap으로 표면화
206+
- 전체 시장 원천 DART와 EDGAR continuation과 subject-only PIT feature 범위를 명시적으로 분리
207+
- 공통 feature, actual owner, catalog, query, simulator 집중 회귀 93건 통과
208+
- 작업대 핵심, simulator, architecture, Skill OS 연결 회귀 196건 통과
209+
- continuation, restart, CAS, Arrow, page scan 회귀 207건 통과와 환경 의존 2건 skip
210+
- resource paging과 별도 process resume 회귀 31건 통과
211+
- L0부터 L15 strict guard 7개 규칙, workbench purity, 신규 공개 함수 docstring strict, camelCase, Ruff, targeted Pyright 통과
212+
- 영구 materialization, historical universe, 전종목 계산 feature paging, offline과 online serving은 runtime SSOT 불가능 실측, 사전 설계 토론, 명시 승인 전 미구현 상태 유지

mainPlan/unified-data-workbench/06-full-certification-and-hardening.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@ Data Workbench 공통 계층은 signature-grade로 판정한다. 이유는 일
1010

1111
| 항목 | 실측 |
1212
|---|---:|
13-
| 전체 asset | 353 |
14-
| queryable | 170 |
13+
| 전체 asset | 354 |
14+
| queryable | 171 |
1515
| catalog-only | 183 |
1616
| engineAxis | 146 |
17-
| callable | 1 |
17+
| callable | 2 |
1818
| resource locator | 23 |
1919
| L1 queryable | 39 |
2020
| L1.5 queryable | 28 |
21-
| L2 queryable | 103 |
21+
| L2 queryable | 104 |
2222

2323
`gather.calendar`는 registry에 남아 있지만 호출하면 항상 폐기 예외를 내므로 `queryable=False``executorKind=catalog`로 바로잡았다. catalog에서 삭제하지 않아 폐기 이유와 drift는 계속 추적된다.
2424

2525
## 3. 전수 계약 인증
2626

27+
아래 표는 W8 당시 queryable 170개 baseline이다. W10의 171번째 callable asset은 공통 feature 집중 회귀와 실제 AAPL smoke로 별도 인증했으며 §8에 기록한다.
28+
2729
| gate | 범위 | 결과 |
2830
|---|---:|---:|
2931
| executor 해소 | queryable 170 | 170 통과 |
@@ -102,7 +104,15 @@ quant.entry와 quant.style은 `dipBuy`가 등록하지 않은 camelCase Signal k
102104

103105
- runtime `timeoutMs`는 owner Python 호출을 강제 종료하지 못하는 협력적 제한이다. 전수 인증 runner는 프로세스 격리로 이 한계를 보완했다.
104106
- row와 byte budget은 owner 결과를 받은 뒤 projection에서 적용된다. owner별 predicate, projection, slice pushdown은 별도 최적화가 필요하다.
105-
- 실제 knownAt vintage를 제공하는 asset은 아직 없다. latest-only를 과거 성공으로 꾸미지 않는 fail-closed가 현재 정답이다.
106-
- Arrow table 변환은 완료됐지만 네트워크 Arrow Flight server와 continuation token은 아직 transport 확장 범위다.
107+
- `analysis.edgarFinancialFeatures`실제 filing cutoff를 쓰는 knownAt feature를 제공하지만, retained companyfacts가 historical admission snapshot 전체를 보존하지 않아 exact가 아니라 conditional이다.
108+
- raw DART와 EDGAR resource는 opaque continuation을 지원한다. 전종목 계산 feature paging과 네트워크 Arrow Flight server는 아직 확장 범위다.
107109

108110
따라서 현재 제품은 단일 프로세스와 외부 Python 소비에 강력한 범용 데이터 작업대다. 분산 서버에서 hard cancellation, streaming, owner pushdown까지 갖춘 최종 물리 플랫폼이라고 부르지는 않는다.
111+
112+
## 8. 2026-07-23 revision-aware feature 확장
113+
114+
data 공통 계층에 feature registry, observation, vintage, revision-aware query 계약을 추가했다. `analysis.edgarFinancialFeatures`는 subject와 knownAt을 받는 두 번째 callable asset이며 로컬 EDGAR companyfacts에서 operating-company reduced financial feature를 만든다. catalog는 354개, queryable은 171개가 됐다.
115+
116+
AAPL 실제 로컬 smoke에서 revenue와 operating margin 두 feature를 한 공개 query로 반환했다. 관측의 `knownAt`은 query cutoff가 아니라 실제 최대 filing date였고, 인접 cutoff는 같은 evidence에 대해 동일 observation ID와 revision ID를 유지했다. 현재 보존 이력의 한계는 `latestRetained`, `periodOnly`, `conditional`로 표시했다.
117+
118+
이 확장은 전종목 raw resource continuation을 전종목 factor store로 바꾸지 않는다. 현재 feature callable은 `subjectFanout`이다. 영구 materialization, historical universe, 전종목 계산 feature paging, offline과 online serving은 runtime SSOT로 불가능하다는 실측, 별도 atomic generation 설계 토론, 명시적 아키텍처 승인 뒤에만 코드와 실행을 진행한다.

mainPlan/unified-data-workbench/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# DartLab Unified Data Workbench
22

3-
상태: 구현, 전수 라우팅과 projection 인증, 170개 실제 물질화 감사, 외부 설치 검증 완료. 2026-07-22 저장소 실측과 공식 외부 설계 조사를 반영한다.
3+
상태: 구현, 전수 라우팅과 projection 인증, 170개 실제 물질화 감사, 171개 queryable catalog, 외부 설치 검증 완료. 2026-07-23 저장소 실측을 반영한다.
44

55
## 한 문장 정의
66

@@ -24,6 +24,8 @@
2424
12. partition은 구조화 lineage, quality assertion과 Arrow transport를 제공한다.
2525
13. catalog `snapshotId`와 실제 반환 content의 `dataSnapshotId`를 분리하고 partition마다 `contentHash`를 둔다.
2626
14. 전종목 continuation은 첫 `DataResult``iterPages()` 또는 `iterAllArrowBatches()`가 자동 소비한다.
27+
15. feature registry, observation, vintage, PIT query는 data 공통 계약이며 simulator와 외부 소비자가 같은 의미 규칙을 쓴다.
28+
16. 전종목 원천 paging과 계산된 전종목 factor paging은 구분한다. 현재 EDGAR PIT feature는 subject 단위 callable이다.
2729

2830
## 공개 계약
2931

@@ -45,6 +47,8 @@ result = dartlab.data(
4547
)
4648
```
4749

50+
같은 진입점에서 `analysis.edgarFinancialFeatures``knownAt``FactorProjection`으로 요청하면 실제 filing cutoff를 보존한 revision-aware feature row를 얻는다. 현재 retained companyfacts의 이력 한계 때문에 이 자산은 `latestRetained`, `periodOnly`, `conditional`로 정직하게 반환한다.
51+
4852
`DataResult`는 최소한 `status`, `partitions`, `assets`, `snapshotId`, `dataSnapshotId`, `contractHash`, `coverage`, `gaps`, `lineageRefs`, `executionReceipts`, `continuation`을 함께 가진다. schema와 실제 값의 `contentHash`는 각 partition이 보존한다.
4953

5054
## 문서 지도

src/dartlab/analysis/dataProduct.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,37 @@
2929
"temporalSupport": ("latest", "validAt"),
3030
"metadata": {"stockRequired": True, "returnType": "dict"},
3131
},
32+
{
33+
"assetId": "analysis.edgarFinancialFeatures",
34+
"kind": "featureSet",
35+
"label": "EDGAR 영업회사 축약 재무 feature",
36+
"description": "로컬 companyfacts에서 knownAt 기준으로 구성한 조건부 축약 재무 관측",
37+
"executor": {
38+
"module": "dartlab.analysis.financial.dataAssets",
39+
"attribute": "edgarFinancialFeatures",
40+
},
41+
"sourceModules": (
42+
"dartlab.analysis.financial.filingFeatures",
43+
"dartlab.analysis.financial.edgarPitState",
44+
"dartlab.analysis.financial.stepProjection",
45+
"dartlab.providers.edgar.finance.facts",
46+
),
47+
"subjectParam": "subject",
48+
"knowledgeTimeParam": "knownAt",
49+
"temporalSupport": ("knownAt",),
50+
"selectorKind": "subject",
51+
"selectorRequired": True,
52+
"executionMode": "subjectFanout",
53+
"universeMarkets": ("US",),
54+
"metadata": {
55+
"definitionVersion": "edgar-reduced-operating-financial-features-v1",
56+
"featureCoverage": "reducedOperatingCompany",
57+
"knownAtRequired": True,
58+
"market": "US",
59+
"observationPIT": True,
60+
"returnType": "feature-observation-input-v1",
61+
"stockRequired": True,
62+
},
63+
},
3264
),
3365
}

src/dartlab/analysis/financial/dataAssets.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ def simulationInputs(
5858
raise ValueError("simulationInputs는 subject 또는 company가 필요합니다")
5959
import dartlab
6060

61-
company = dartlab.Company(subject)
61+
companyFactory = getattr(dartlab, "Company")
62+
company = companyFactory(subject)
63+
resolvedCompany: Any = company
6264
try:
63-
quarterly = company._buildFinanceSeries(freq="Q")
65+
quarterly = resolvedCompany._buildFinanceSeries(freq="Q")
6466
except (ValueError, KeyError, AttributeError):
6567
quarterly = None
6668
rawSeries = quarterly[0] if isinstance(quarterly, tuple) and len(quarterly) >= 2 else None
@@ -78,3 +80,50 @@ def simulationInputs(
7880
"latestAsOf": latestAsOf,
7981
"requestedAsOf": requestedAsOf,
8082
}
83+
84+
85+
def edgarFinancialFeatures(
86+
*,
87+
subject: str | None = None,
88+
company: Any | None = None,
89+
knownAt: str,
90+
) -> dict[str, Any]:
91+
"""로컬 EDGAR evidence에서 operating-company PIT feature envelope를 만든다.
92+
93+
Args:
94+
subject: US ticker 또는 Company가 해소할 수 있는 EDGAR identity.
95+
company: 테스트와 read-once 조합을 위한 기존 EDGAR Company.
96+
knownAt: SEC filing knowledge cutoff.
97+
98+
Returns:
99+
Data Workbench가 검증하고 FactorProjection으로 변환할 plain mapping.
100+
101+
Raises:
102+
ValueError: Subject가 없거나 EDGAR Company가 아니거나 coherent reduced state가 없을 때.
103+
FileNotFoundError: 현재 runtime에 local companyfacts shard가 없을 때.
104+
105+
Example:
106+
``payload = edgarFinancialFeatures(subject="AAPL", knownAt="20250201")``
107+
"""
108+
109+
if company is None:
110+
if not subject:
111+
raise ValueError("edgarFinancialFeatures는 subject 또는 company가 필요합니다")
112+
import dartlab
113+
114+
companyFactory = getattr(dartlab, "Company")
115+
company = companyFactory(subject)
116+
resolvedCompany: Any = company
117+
cik = getattr(resolvedCompany, "cik", None)
118+
ticker = str(getattr(resolvedCompany, "ticker", subject or "")).strip().upper()
119+
if not cik or not ticker or ticker.isdigit():
120+
raise ValueError("edgarFinancialFeatures는 canonical ticker가 있는 EDGAR Company가 필요합니다")
121+
from dartlab.analysis.financial.filingFeatures import buildEdgarFinancialFeatureInput
122+
from dartlab.providers.edgar.finance.facts import readCompanyFactsLocal
123+
124+
facts = readCompanyFactsLocal(str(cik))
125+
return buildEdgarFinancialFeatureInput(
126+
facts,
127+
entityId=f"US:{ticker}",
128+
knownAt=knownAt,
129+
)

0 commit comments

Comments
 (0)