Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/adr/stock_data_source_boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ADR: Stock-data source acquisition and transport ownership

Status: Proposed. Date: 2026-09-07. Canonical identity: `stock_data_source_boundary` (semantic filename avoids collisions with the numbered ADR stack in PR #149).

## Problem and evidence

The user requested stock-data collection through CWL libraries. At protected `develop@e550688c80f0dcf4677c0fbe50bd3341429106fb`, mightyETL has a Java ETL host and database/CDC connectors, but no discovered stock-source implementation. An organization code search and a focused open-PR search did not identify an existing stock collector; this is an inventory observation, not proof about private deployments. EgressWeave's protected README describes a Python HTTPX library. OriginWeave's protected README explicitly says its HTTP adapters are not shipped; its release listing returned no releases.

The FSC public-data portal describes daily stock-price/volume data and explicitly states that reference-day data is supplied after 13:00 on the following business day. The introductory marketing phrase about realtime information must not override that operational notice. A Friday result may arrive on Monday or later when holidays intervene. An empty response is not proof of a holiday or a completed publication.

## Alternatives and choice

1. HTML scraping in a product consumer: rejected. It would duplicate acquisition policy, depend on page markup and tempt unsupported fallback after authorization failures.
2. Python/yfinance inside the Java service: rejected. It adds a second consumer runtime and an unverified provider/licensing path for convenience.
3. A new market-data service and financial database: deferred. No independent domain-truth or transaction boundary is needed just to retrieve provider records.
4. A source adapter in mightyETL, behind an explicit governed transport: chosen. The Java code is provider anti-corruption/host glue, not a new numerical analytics or security runtime. It uses JDK exact-value types without rounding or financial inference. Rust remains the implementation policy for new shared numerical and security/performance runtimes. A future Rust network binding belongs to EgressWeave, not a copied consumer client.

## Implemented candidate contract

`FscStockDataSource.collectStockData` accepts an inclusive reference-date range, optional exact ISIN, and bounded pagination budgets. It submits secret-free page requests through `StockDataTransport`; the host transport must resolve a deployment-owned credential reference and materialize `serviceKey` once. There is no built-in HTTP client, network fallback, Spring registration, scheduler, REST endpoint, SQL write or LLM call.

The adapter validates the UTF-8 XML envelope and success code, response page number and size, stable total count, exact expected row count, date/filter membership, identifier grammar, duplicate date/ISIN identity, bounded exact numeric fields and OHLC ranges. It retains source zeroes only when consistent with the range rules; absent/invalid values never become zero. This is not full exchange-rule validation or ISIN-checksum certification.

A complete batch is returned only after every page passes. Raw transfer-decoded XML bytes and SHA-256 digests are retained with per-page `collectedAt`. The provider reference date, observation time, `Asia/Seoul`, `KRW`, `delayed_daily`, and `provider_unspecified` adjustment basis remain distinct. No holiday, publication timestamp, corporate-action adjustment or realtime quote is inferred.

Bounds are consumer safety budgets, not claimed provider quotas: 366 inclusive calendar days, 1,000 rows/page, 100 pages, 10,000 records, 2 MiB/page and 16 MiB raw bytes/batch. Exceeding a budget fails the request instead of silently truncating. Large backfills must be partitioned explicitly by the host and retain separate collection receipts.

XML processing denies DTDs, external entities, schemas and XInclude, limits element depth, and suppresses provider/parser diagnostics. Structural `response`, `header`, and `body` children must match the declared envelope; unknown or duplicate structural elements fail the page. Provider-defined fields remain allowed only inside `item`. Transport errors, including close/suppressed failures, do not expose URLs, keys or payloads. Cancellation is checked before acquisition, after body delivery/read, after XML decode/validation, and immediately before a completed batch can escape; response ownership is closed on every outcome.

## Ownership and interoperability

mightyETL owns provider query/field mapping and collection receipts. EgressWeave owns destination authorization, actual socket/DNS pinning, TLS, credentials, transport deadlines, rate/concurrency limits and response framing. The interface is a port, not evidence that those controls have run. Owner issue [EgressWeave #246](https://github.com/ContextualWisdomLab/EgressWeave/issues/246) specifies the missing released cross-language binding and hostile/live conformance gates.

A financial product owns market-data revisions, trading decisions and its database. This adapter does not write `processed_data` or route stock prices through the existing generic AMOUNT transformation. Context Graph Contracts and Enterprise Architecture Core remain read-only dependencies for this slice; no domain schema is copied into their repositories. A future catalog publication must reference a released source contract rather than copy observations into a catalog truth store.

## Risks, acceptance and rollback

Stable counts and duplicate checks detect common pagination corruption but do not prove an upstream transactional snapshot. The provider can revise data without changing its total count. Preserve raw pages and separate per-page observation times; do not advertise snapshot isolation or point-in-time backtest safety.

Local verification covers synthetic unit inputs only. A provider key and real source response were not available. The official portal was inspected, but the complete primary wire guide was not retrieved; wire-profile approval and actual keyed retrieval remain release gates. Full Java 25 Maven CI, measured 100% production coverage, independent review, security/provenance and immutable release evidence are still required. Java 21 focused compilation is development evidence, not a replacement for the repository's Java 25 support gate.

Before production use, complete #246, adopt its immutable release, verify the primary wire profile and run a known-day FSC request plus rate-limit/credential/close-path conformance. There is no automatic activation to roll back. Removing this package removes only the new source capability; existing ETL/CDC behavior and stored data are unchanged.

Root PRD/TRD/README/AGENTS/CLAUDE/CHANGELOG remain in canonical documentation PR #149's ownership. This path-disjoint ADR and the linked stock-specific specification supply the feature delta for ordinary later integration, not a competing whole-file rewrite.

References and source-to-test mapping: [doctoring](../doctoring/fsc_stock_data_sources.md). Usage/specification: [stock source](../stock_data/stock_source_specification.md). Current scope: [gap baseline](../product-technical-gap-baseline.md).
9 changes: 9 additions & 0 deletions docs/changes/stock_data_source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Unreleased candidate: FSC stock-source acquisition

Add a Java provider adapter in the existing mightyETL ETL host for bounded FSC stock queries, typed exact values, complete-result pagination validation, immutable raw-page evidence and safe cancellation/error/stream handling. No new runtime dependency or workflow is introduced; JUnit invokes the same focused executable contracts.

The source requires an explicit approved transport. It is not yet a released/live-provider-verified capability. EgressWeave #246 owns the missing immutable cross-language transport binding. The full primary wire guide, real keyed retrieval, Java 25 reactor, coverage, security and independent review remain release gates.

Hourly fire 2026-09-08: review findings on Draft #333 were verified against `06ccc7f`. Late cancellation after body read can no longer return a completed batch; undeclared structural XML children are rejected; contract checks now cover cumulative batch-byte overflow, read/close failures, and an exact SHA-256 digest. The code-quality comment on `StockBatch.priceRecords()` remains a false positive: the private constructor already stores `List.copyOf`. No HTTP client was added.

This fragment is supplied to canonical documentation PR #149 rather than rewriting its concurrently owned root CHANGELOG/PRD/TRD/README/AGENTS/CLAUDE files. Merge it into the root changelog only with the actual integrated feature and its evidence; do not backdate a release or mark a Proposed ADR Accepted solely because code exists.
34 changes: 34 additions & 0 deletions docs/doctoring/fsc_stock_data_sources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# FSC stock-source evidence and decision traceability

Access date: 2026-09-07. Only the following primary documents are cited as authorities. Operational and source-code observations are separate from future acceptance requirements.

## References (APA 7)

Financial Services Commission. (n.d.). *금융위원회_주식시세정보*. Public Data Portal. https://www.data.go.kr/data/15094808/openapi.do

Oracle. (n.d.). *Java API for XML Processing (JAXP) security guide*. Java Platform, Standard Edition 25 Security Developer's Guide. https://docs.oracle.com/en/java/javase/25/security/java-api-xml-processing-jaxp-security-guide.html

Oracle. (n.d.). *Class BigDecimal*. Java Platform, Standard Edition 25 API specification. https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html

## Evidence boundaries

The FSC portal explicitly says daily reference data is available after 13:00 on the next business day, offers XML/JSON REST data and requires an API application/key. This supports the delayed-daily classification and explicit credential boundary. It does not prove a particular local credential is approved, that a given day is complete, or that a transport implementation has passed conformance. The full attached primary wire guide was not retrieved in this run. Parameter/field mapping remains a candidate profile until the guide and a real keyed request are verified; third-party examples are not promoted to primary authority.

The JAXP guide explains why default secure-processing settings alone should not be treated as external-resource denial. The decoder explicitly disables DTDs, external entity/schema access and XInclude, sets a depth limit, selects the JDK factory and uses strict UTF-8 decoding. Hostile XML contracts exercise the source boundary. They do not prove an upstream socket is governed; that belongs to EgressWeave.

BigDecimal supports exact decimal representation. The adapter constructs from validated source text and performs no rounding or return/risk calculations. BigInteger retains whole-number quantities without IEEE-754 precision loss. These are provider type conversions, not a new financial analytics engine.

## Traceability

| Authority / concern | Source implementation | Executable evidence |
|---|---|---|
| FSC publication timing | `StockBatch.freshnessClass`, raw-page timestamps | `verifyCompleteCollection`, `verifyEmptyAndSingleton` |
| Query/pagination integrity | `collectStockData`, `StockPageDecoder.decodePage` | `verifyInvalidPages`, `verifyQueryRejection` |
| Exact source values | `StockPriceRecord`, decoder numeric functions | `verifyCompleteCollection`, `verifyInvalidRecords` |
| JAXP external resource limits | `StockPageDecoder.readDocument` | `verifyHostileXml`, `verifyTransportFailures` |
| Declared envelope cardinality | `StockPageDecoder.requireChildren` | extra/duplicate `response`/`header`/`body`/`items` cases in `verifyHostileXml` |
| No key/diagnostic export | `fetchBody`, request/response formatting, finite exception | `verifyTransportFailures`, `verifyLateCancellationAndSafeFormatting` |
| Response lifecycle | `PageResponse.close`, `fetchBody` | rejected/oversized/cancelled-body close assertions; read/close and close-with-primary failures |
| Late cancellation | `requireNotCancelled` after decode and before batch return | Clock.instant() interrupt in `verifyLateCancellationAndSafeFormatting` |

The local compiler is OpenJDK 21.0.11. After the 2026-09-08 review repairs, `sh scripts/verify_stock_data_source.sh` passed 299 synthetic assertions plus `javac -Xlint:all -Werror` and `javadoc -Werror -Xdoclint:all`. This is not 299 independent JUnit methods and not a 100% coverage measurement. The repository's Java 25 Maven reactor, security checks, independent review and immutable release remain mandatory.
63 changes: 63 additions & 0 deletions docs/product-technical-gap-baseline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Product / technical gap baseline

Observed 2026-09-08 (hourly fire). Protected baseline: `develop@e550688c80f0dcf4677c0fbe50bd3341429106fb`. Canonical broader documentation remains in open Draft PR #149. Open work is candidate/proposed, not shipped truth. Keep Product Requirements Document names and case: Change Data Capture (CDC), Extract-Transform-Load (ETL), JWT, Eureka, Config Server.

## PRD vs evidence

| PRD capability | Current evidence | Remaining gap |
|---|---|---|
| Change Data Capture from PostgreSQL | Live path Postgres→Kafka; slot probe, replica allow-list, ops docs | Multi-source Debezium engines; MySQL/SQL Server are discovery scaffolds |
| Extract-Transform-Load JSON pipeline | Bounded batches, idempotent retries, RFC 9457 errors, Flyway schema authority; process-path transport admission is on `develop` | Durable job worker/replay/cancellation still stacked as drafts; amount integrity refresh is draft #316; job-intake transport admission is Draft #334, not protected |
| JWT authentication and RBAC | Gateway placeholder-token repair is draft #142; ETL JWT fail-closed is draft #287 | Production JWT resource-server path not on `develop` |
| Qlik Sense / Databricks / Snowflake | SPI + YAML + required-key validation + catalog; writes refused | Live SaaS loaders need credentials and real clients |
| Any-to-any CDC | Source/target SPI; live Postgres→Kafka only | Do not market warehouse loaders as supported |
| Stock observations | Candidate `FscStockDataSource` on Draft #333 | No released transport; no live keyed FSC retrieval |

## TRD / UML

Ports remain: Gateway 8080, ETL 8000, CDC 8001, Eureka 8761, Zipkin 9412. Root `pom.xml` on `develop` pins Java 25, Spring Boot 3.5.16, Spring Cloud 2025.0.3, Debezium 3.4.0.Final. `TRD.md` still names Spring Boot 3.5.9 / Spring Cloud 2025.0.1; that document lag is a remaining gap, not a license to claim the older matrix. UML for stock collection is the sequence in `docs/stock_data/stock_source_specification.md`; the transport participant is an owner port, not a shipped service. Broader architecture diagrams stay with Draft #149.

## Connector / owner linkage

Chicken-and-egg is broken with a minimum port, not a consumer HTTP clone. mightyETL owns `StockDataTransport` and FSC field ACL. [EgressWeave #246](https://github.com/ContextualWisdomLab/EgressWeave/issues/246) remains OPEN and owns destination authorization, TLS, credentials, deadlines, rate limits, and the missing released cross-language binding. OriginWeave HTTP adapters remain unshipped. No default Java HTTP, curl, or Python client is added in this consumer.

Warehouse connectors stay scaffolds. CDC registry snapshot immutability is issue #246 in this repo (distinct from EgressWeave #246).

## Open actions (2026-09-08 hourly)

Non-draft PRs targeting `develop` remain `mergeStateStatus=BLOCKED`; none merged this fire. CodeQL compatibility jobs on #333 failed with `VERDICT_STATE=pending` after a successful dispatch (handshake, not a product defect). Do not stall the loop on that rerun.

| ID | State | Note |
|---|---|---|
| PR #334 | draft | New this fire: job-intake transport admission for #247; local Temurin 25 `EtlJob*` BUILD SUCCESS |
| PR #333 | draft | Stock-data candidate at `72462610`; prior fire repaired envelope/cancel findings; leave Draft |
| PR #330 | blocked | Reusable dependency-review caller; waits on ContextualWisdomLab/.github#1724 |
| PR #328 | needs-review | Config Server authority successor of #327/#322; Strix failed; not merged, so predecessors stay open |
| PR #327 / #322 | needs-review | CHANGES_REQUESTED; do not merge or close while #328 is not protected-integrated |
| PR #326 | needs-review | Hourly central PR maintenance; stale base `d6c6665`; Scorecard failed |
| PR #321 | needs-review | Replication-probe confidentiality; all listed checks SUCCESS, still blocked on review; one CodeRabbit minor on log assertion |
| PR #329 | draft | CDC semantic identifiers |
| Draft stack #254/#256 and older durable-job PRs | draft | Stacked on non-`develop` bases; restack later, do not close |
| Issue #247 | open | Process-path admission is on `develop`; jobs path successor is Draft #334 |
| Issue #252 | open | Fail closed before protected merges on non-qualifying evidence |

Displayed closed is not done. No PR was closed this fire.

## Stock-data candidate (Draft #333)

| Buyer gap | Candidate action | Evidence / remaining gate |
|---|---|---|
| No discovered stock-source adapter | `FscStockDataSource.collectStockData` and typed provider ACL | Added source and executable unit contracts; not protected/released until PR integration |
| A partial history can look complete | Validate page identity, total, row count and duplicate date/ISIN; fail whole call | Focused synthetic unit tests; no upstream snapshot-isolation claim |
| Lost leading zeroes or numeric precision | Strings, `BigDecimal`, `BigInteger`; retain raw pages | Leading-zero, fractional-price and >2^53 assertions |
| Delayed/empty data confused with live trading | `delayed_daily`, `empty_source_result`, source date separate from collection time | Official FSC portal notice; no market-calendar inference |
| Malformed provider envelope accepted | Reject undeclared/duplicate structural XML children | Review P1 on #333; envelope tests added this fire |
| Late cancel returned success | Check interrupt after decode and before batch return | Clock.instant() interrupt contract added this fire |
| No verified released cross-language HTTP authority | Explicit transport port, no automatic network implementation | EgressWeave #246: owner runtime, release and consumer conformance required |
| Provider wire/profile not fully verified | Bound the candidate mapping and preserve unknown fields/raw bytes | Official portal inspected; full primary guide and actual keyed known-day retrieval still required |
| Test/release acceptance incomplete | Existing JUnit entrypoint; warning-free local compile and Javadoc | Local Java 21 subset; full Java 25 Maven, coverage, security, review, immutable release not proven |
| Durable stock store / revision history absent | Do not mutate generic `processed_data` or create cross-service SQL | Market-data domain owner, archive/revision API, migrations and real DB tests remain separate work |

Source documentation: [ADR](adr/stock_data_source_boundary.md) (Proposed, not Accepted), [PRD/TRD/API/UML slice](stock_data/stock_source_specification.md), [doctoring](doctoring/fsc_stock_data_sources.md), [change fragment](changes/stock_data_source.md), [implementation plan](superpowers/plans/2026-09-07-stock-data-source.md).

This fire does not mark the ADR Accepted, claim UI completeness, force-push, or advertise live stock crawling. No existing PR was closed, superseded, or stripped of valid delta. Draft #334 is an independent Extract-Transform-Load availability successor, not a replacement for #333.
Loading
Loading