v4.0.0
The ETL now says whether what it produced is well formed and the API serves that verdict. ontology/shapes.ttl holds SHACL shapes for entities, positions, instruments and filings, covering cardinality, datatypes, the ten digit CIK pattern, ownership fractions between 0 and 1 and the closed instrument class vocabulary. tradegraph-etl validate runs them with pyshacl and adds the three checks that belong to the dataset rather than to a single node, dangling references, subsidiaryOf cycles and issuers carrying neither a CIK nor a ticker, writing the result to etl/build/quality.json; --fail-on-violation makes it exit non zero, which is what CI now runs. The shapes earned their place on the first run by catching a real defect: a listed asset manager's Exhibit 21 filing shared an accession number with its own first 13F, so 13F filings in the sample are now numbered from 1000. GET /quality serves the report of the last load and answers 404 when there is none, and tradegraph-etl load --since only pushes the graph files that moved, so a rebuild that touched one graph replaces one graph instead of three. Tests are 40 ETL pytest, 45 API unit, 22 Testcontainers integration and 9 explorer specs, all green against Fuseki.