diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b364318e8..4b4bcfc88 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -66,11 +66,8 @@ boundaries above remain the target modular MSA architecture. | `persistence_postgres` | PostgreSQL repositories and migrations | | `corpus_split` | cutoff-safe, relation-aware partitioning | | `tepp_simulation` | known-truth temporal/event data generation | -| `validation_core` | RMSE, bias, coverage, graph, and Monte Carlo metrics | -| `tepp_api` | versioned DTO, schema, terminal-result, and export contracts | -| `location_membership` | location is not entity identity and not a language channel | | `validation_core` | RMSE, bias, coverage, graph, Monte Carlo, and exact-head claim-promotion metrics | -| `tepp_api` | versioned DTO, schema, and export contracts | +| `tepp_api` | versioned DTO, schema, terminal-result, and export contracts | | `prompt_source` | prompt boilerplate is not unique latent content and not stopword deletion | | `corpus_background` | corpus-background wording is not unique latent content and not stopword deletion | | `modality_source` | non-lexical modality is not unique latent content and not stopword deletion | diff --git a/CHANGELOG.md b/CHANGELOG.md index c45ef29d0..d3be1cdc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,9 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang - Quality-gate coverage tests now exercise blank-predecessor structural commas and escaped character literals in the authored-line scanner, including the past-EOF fail-closed path. - Restored Graham Neubig's correct APA 7 initial in the Liu et al. (2023) prompting-survey register entry after the protected-main rebase. - After protected-main consolidation #215, the analysis-run execution decision is recorded as ADR 0022 so it does not collide with ADR 0021 LineageWeave project-history. +- After the protected-main merge of #49/#58/#65, README keeps one balanced crate list of all 54 workspace members, including `topic_measurement`, `analysis_engine`, and `psychometric_core`. +- Coverage JSON unique-fold no longer leaves a shadowed duplicate `load_union_branch_totals`; the live helper still unions True/False counts across instrumented copies and fail-closes on malformed records. +- The architecture foundation-crate table keeps one `location_membership`, one `validation_core`, and one `tepp_api` row after the #48 merge, and the API row retains terminal-result contracts. - Registered the analysis-engine gap-closure doctoring in the canonical documentation map so its product and scientific traceability record is discoverable. - Authored Rust coverage classification now ignores standalone structural closing parentheses, preventing formatting-only LCOV rows from appearing as uncovered production behavior. - `analysis_engine` vertical slice (ADR 0022): bounded Rust execution from an accepted analysis run to either a cutoff-safe readiness result or a validated `tepp.trsl_topic_lineage.v1` artifact from the ADR-0012 estimator. Topic artifacts preserve fitted predecessor/successor edges, connectable-post and lineage counts, request/snapshot/cutoff bindings, SHA-256 identity, and fail-closed non-convergence/tamper behavior with exact line/branch coverage. This remains active-PR evidence and does not claim causal or psychometric authority. diff --git a/README.md b/README.md index c01103754..796c0b065 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,11 @@ implemented in Rust. ## Current implementation state -The repository currently implements 53 independently documented crates rather -than a full commercial release. The implemented crates include topic measurement -and the analysis engine; they do not claim a complete commercial estimator, -operator workspace, or supported release. +The repository currently implements 54 independently documented crates rather +than a full commercial release. The implemented crates include topic +measurement, the analysis engine, and psychometric input/recovery gates; they +do not claim a complete commercial estimator, operator workspace, or supported +release. - `topic_measurement`: the first production topic-measurement crate. It estimates topic proportions from observed counts, maps those proportions into @@ -21,29 +22,11 @@ operator workspace, or supported release. estimator contract; persists the run with the six TEPP clocks; and emits a typed terminal result. The crate does not claim buyer-visible product completeness. +- `psychometric_core`: validated statistical-recovery APIs on already-mapped + coordinates. It does not implement a full ESEM/DSEM estimator. ```text crates/analysis_engine -These are production contracts, not a claim that the complete commercial -estimator, operator workspace, or supported release already exists. Read the -[product and technical gap baseline](docs/product-technical-gap-baseline.md) -before treating a crate as a shipped product capability. -This branch keeps the Rust workspace quality foundation and the bounded -foundation crates. Domain crates expose only tested contracts: immutable -evidence, six-clock temporal values, event mentions/instances, relations, -membership, persistence, splits, simulation, validation, API DTOs, and the -predicted-versus-observed promotion gate. -This branch establishes the Rust workspace, quality-gate foundation, and the -longitudinal within/between decomposition capability. The eleven bounded crates -compile independently. `longitudinal_core` exposes within/between decomposition -and component RMSE APIs; the remaining crates expose no placeholder production -APIs, and domain behavior for them begins in Task 2 with immutable evidence -identifiers and source records. -This branch establishes the Rust workspace and quality-gate foundation. The -bounded crates compile independently. Domain crates expose only validated -production APIs; placeholder surfaces are prohibited. - -```text crates/assertion_clock crates/available_clock crates/checkpoint_authority @@ -59,39 +42,6 @@ crates/document_clocks crates/encrypted_mapping crates/episode_membership crates/event_clock -crates/evidence_core -crates/semantic_core -crates/temporal_core -crates/event_core -crates/evidence_core -crates/inferred_status -crates/intake_authorization -crates/interpretation_gateway -crates/location_membership -crates/longitudinal_core -crates/membership_core -crates/membership_target -crates/modality_source -crates/model_selection -crates/network_analysis -crates/operational_log -crates/outcome_order -crates/payload_bound -crates/persistence_postgres -crates/prediction_contradiction -crates/prompt_source -crates/provider_receipt -crates/corpus_background -crates/modality_source -crates/copied_text -crates/copy_identity -crates/corpus_background -crates/corpus_split -crates/cutoff_clock -crates/derived_sensitivity -crates/document_clocks -crates/encrypted_mapping -crates/event_clock crates/event_core crates/evidence_core crates/inferred_status @@ -117,7 +67,6 @@ crates/relation_graph crates/retrospective_edge crates/revision_order crates/semantic_core -crates/operational_log crates/service_tls crates/stopword_deletion crates/style_source @@ -131,14 +80,6 @@ crates/tepp_simulation crates/topic_lineage crates/topic_measurement crates/validation_core -crates/network_analysis -crates/interpretation_gateway -crates/model_selection -crates/checkpoint_authority -crates/compute_backend -crates/episode_membership -crates/membership_target - ``` ## Local verification @@ -178,6 +119,7 @@ made by this foundation slice. The active stacked analysis-engine slice adds a bounded executable readiness path from an accepted run to a digest-bound terminal artifact. It is not yet implemented-main and does not replace scientific estimator contracts. + Validated statistical-recovery APIs exist only inside `psychometric_core`: OLS loading recovery on already-mapped coordinates, posterior-draw point estimates, the Rubin total-variance identity `T = U_bar + (1 + 1/m) B`, CWC/event-time/ diff --git a/scripts/check_coverage.py b/scripts/check_coverage.py index b7230153d..bb2809d57 100644 --- a/scripts/check_coverage.py +++ b/scripts/check_coverage.py @@ -37,45 +37,6 @@ def load_totals(path: Path) -> Mapping[str, Any]: return merged -def load_union_branch_totals(files: Sequence[object]) -> Mapping[str, int | float]: - """Merge LLVM branch outcomes by source coordinate across test binaries.""" - - outcomes: dict[tuple[str, int, int, int, int], list[int]] = {} - for file_record in files: - if not isinstance(file_record, Mapping): - raise ValueError("coverage file record must be an object") - filename = file_record.get("filename") - if "branches" not in file_record: - raise ValueError("coverage file record must contain branches") - branches = file_record["branches"] - if not isinstance(filename, str) or not filename: - raise ValueError("coverage file record must contain a filename") - if not isinstance(branches, list): - raise ValueError("coverage branches must be a list") - for branch in branches: - if not isinstance(branch, list) or len(branch) < 6: - raise ValueError("coverage branch record is malformed") - coordinates = branch[:4] - counts = branch[4:6] - if not all( - isinstance(value, int) and not isinstance(value, bool) and value >= 0 - for value in coordinates - ): - raise ValueError("coverage branch coordinates are invalid") - if not all( - isinstance(value, int) and not isinstance(value, bool) and value >= 0 - for value in counts - ): - raise ValueError("coverage branch counts are invalid") - key = (filename, *coordinates) - outcome = outcomes.setdefault(key, [0, 0]) - outcome[0] += counts[0] - outcome[1] += counts[1] - count = len(outcomes) * 2 - covered = sum(outcome > 0 for counts in outcomes.values() for outcome in counts) - return {"count": count, "covered": covered} - - def _parse_branch_record(record: object) -> tuple[tuple[int, int, int, int], int, int]: """Return ``(site, true_count, false_count)`` from one LLVM branch tuple. diff --git a/tests/quality/test_check_coverage.py b/tests/quality/test_check_coverage.py index 3e0edf726..86451f2bc 100644 --- a/tests/quality/test_check_coverage.py +++ b/tests/quality/test_check_coverage.py @@ -342,6 +342,28 @@ def test_full_branch_reports_fail_closed_on_malformed_records(self) -> None: with self.assertRaisesRegex(ValueError, message): coverage_contract.load_union_branch_totals(files) + def test_union_branch_totals_merge_valid_copies_across_files(self) -> None: + """Valid records union True/False counts across instrumented copies.""" + + files = [ + { + "filename": "src/live.rs", + "branches": [[10, 4, 10, 12, 1, 0, 0, 0, 4]], + }, + { + "filename": "src/live.rs", + "branches": [[10, 4, 10, 12, 0, 1, 0, 0, 4]], + }, + ] + self.assertEqual( + coverage_contract.load_union_branch_totals(files), + {"count": 2, "covered": 2}, + ) + self.assertEqual( + coverage_contract.load_union_branch_totals([]), + {"count": 0, "covered": 0}, + ) + def test_lcov_authored_line_totals_and_incomplete_detection(self) -> None: """LCOV counts unique authored source lines and exposes zero-hit lines."""