Skip to content
Merged
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
14 changes: 7 additions & 7 deletions ENGINEERING_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

| Field | Current state |
| --- | --- |
| Current program | Generation 2 — TDE 1.0 DJConnect Enablement Program |
| Lifecycle state | `RC2_CANDIDATE_PREPARATION_REVIEWABLE_FROZEN`; G2-A, G2-B, and G2-C are complete and the remaining 1.0 work is deliberately bounded. |
| Current branch | `codex/rc2-candidate-preparation` |
| Current decision | `TDE_1_0_0_RC2_CANDIDATE_PREPARATION_READY` |
| Repository truth | `0.2.0` is published and qualified. Generation 1 is complete. G2-A completed public CLI, baseline/differential, and qualification proof, then validated fresh post-merge branch-coverage artifacts from `djconnect` and `djconnect-pi`; TDE does not run tests or generate coverage. G2-B covers the eight active DJConnect repositories with native pip, npm, NuGet, SwiftPM, and PlatformIO evidence where applicable. G2-D has three successful `djconnect-pi` Observe runs using the exact public `0.2.0` CLI; the retained artifacts and limitations are recorded in [the Phase 1 Observe record](docs/djconnect-observe-pilot.md). |
| Current program | TDE 1.1 — Cross-language Complexity Policy Parity |
| Lifecycle state | `IMPLEMENTATION_REVIEWABLE`; TDE 1.0.5 and all seven Observe-only integrations are complete. |
| Current branch | `codex/tde-1-1-complexity-parity` |
| Current decision | `ADR-0065_CROSS_LANGUAGE_COMPLEXITY_POLICY_PARITY` |
| Repository truth | `1.0.5` is the current published runtime. The authorized 1.1 increment retains the four capability public contract and adds canonical primary-language complexity adapters without changing thresholds, qualification semantics, or Observe-only governance. |
| Coverage baseline | `djconnect`: 87.73% lines and 68.91% branches; `djconnect-pi`: 75.10% lines and 62.38% branches; `djconnect-website`: 96.59% lines and 82.86% branches; `djconnect-esp32`: 88.83% lines and 60.53% branches. Each fresh G2-A completion artifact is `VALID` with `QUALIFIED` runtime. |
| Dependency-health baseline | All eight repositories produced valid, qualified capability evidence. Current outdated findings: `djconnect` 3, `djconnect-api` 4, `djconnect-website` 1, `djconnect-windows` 15, `djconnect-esp32` 1, and `djconnect-app` 0; `djconnect-pi` is explicitly unavailable because its direct requirements are unpinned; `djconnect-firmware` has no supported manifest. |
| Next planned public release | `1.0.0`, after the immutable `1.0.0rc2` candidate is qualified with the selected consumer, artifacts, Runtime, and release evidence. See [TDE 1.0 Scope Lock](TDE_1_0_SCOPE_LOCK.md). |
| Next planned public release | `1.1.0`, only after public-wheel, adapter and cross-platform qualification evidence is complete and the reviewable release PR is approved. |
| Security decision | G2-C is complete: the factual eight-repository inventory found no selected-pilot decision that justifies a TDE 1.0 security capability. Existing native controls remain the decision owners; see [Security Gap Assessment](SECURITY_GAP_ASSESSMENT.md). |
| Next recommended engineering work | Review and merge RC2 preparation in PR #131, then run the existing non-publishing candidate workflow from its exact merged `main` SHA with candidate version `1.0.0rc2`. The failed RC1 candidates remain immutable NO-GO evidence. Do not promote to warn, soft fail, required, or wider rollout. |
| Next recommended engineering work | Complete adapter/parser/source-classification tests, qualify the exact public wheel, then open one draft PR per selected consumer. Do not merge automatically or alter Observe mode. |

## Deferred Work

Expand Down
9 changes: 9 additions & 0 deletions INTEGRATION_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ TDE is a standalone product. Consumers—including DJConnect—integrate only th

Consumers must never integrate through runtime internals, private adapter APIs, repository layout, or unreleased behavior. Public reusable workflows, if introduced later, are contracts with their own versioning and authorization model; workflow access does not imply artifact or release write access.

## Complexity parity public contract

`tde assess` and `tde qualify` discover a repository's primary product language
from canonical source classification and resolve registered complexity adapters
inside the published runtime. Consumers must only pin the runtime and invoke the
public CLI; they must not install or select Radon/Lizard adapters themselves.
The resulting `complexity.cyclomatic.product.maximum` follows the existing
policy and qualification path. TDE remains Observe-only in consumer workflows.

## Runtime recovery public contract

`tde assess --capability code_size <repository>` is the public entrypoint for
Expand Down
1 change: 1 addition & 0 deletions PRODUCT_BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| Item | Concrete DJConnect value / intended consumer | Acceptance evidence | Explicit non-goals |
| --- | --- | --- | --- |
| Apple coverage improvement | Improve the separately reported Apple product coverage baseline from 38.37% through targeted UI and widget tests when the Apple team schedules the work. | A selected Apple test scope produces a reviewed canonical coverage artifact without changing TDE policy or thresholds. | TDE runtime/capability changes; coverage-threshold changes; treating the current 38.37% baseline as an integration failure. |
| TDE 1.1 complexity policy parity | Establish canonical primary-product-language complexity evidence for the seven selected DJConnect source consumers using one capability, policy and qualification route. | Public 1.1 runtime, adapter qualification, and seven reviewable Observe-only consumer PRs with provenance-rich primary-language complexity evidence. | Policy forks, threshold increases, consumer-local analyzers, automatic product refactoring, merge blocking, security/SBOM/dashboard work. |

## Completed in Generation 2

Expand Down
5 changes: 4 additions & 1 deletion PRODUCT_ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
TDE `1.0.5` is the published and qualified public runtime. DJConnect is the
primary product; TDE is the supporting engineering tool for reliable DJConnect
pipeline decisions. Generation 1 and the bounded Generation 2 delivery are
complete; TDE is now maintenance-first.
complete. TDE 1.1 is the explicitly authorized, bounded cross-language
complexity parity increment.

## Generation 2 active roadmap

Expand All @@ -20,6 +21,8 @@ complete; TDE is now maintenance-first.
Consumer integration remains Observe-only. It does not create required checks,
merge blocks, soft-fails, or consumer-side analyzer and policy duplication.

| TDE 1.1 Cross-language complexity parity | **In progress.** One canonical complexity capability gains primary-product-language evidence for Python, TypeScript/JavaScript, Swift, C/C++, and C#. | Qualified public runtime; one exact public pin in all seven Observe-only consumers; valid primary-language evidence and unchanged policy thresholds. |

## Release and operating model

Capabilities and consumer changes continue to merge in independently
Expand Down
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ DJConnect is the primary product. Technical Debt Engine (TDE) is its compact,
supporting engineering tool for producing reliable pipeline assessment
decisions through public evidence and CLI contracts.

Generation 2 is the consumer-driven **TDE 1.0 DJConnect Enablement Program**.
It does not expand TDE into a general platform: its active scope is coverage
completion, minimal dependency and security evidence, selected DJConnect CI
consumption, and one integrated `1.0.0` qualification and release. See the
[roadmap](PRODUCT_ROADMAP.md) and [active backlog](PRODUCT_BACKLOG.md).

Release `0.2.0` is available as the PyPI distribution
[`technical-debt-engine-runtime`](https://pypi.org/project/technical-debt-engine-runtime/0.2.0/),
a [GitHub Release](https://github.com/pcvantol/technical-debt-engine/releases/tag/0.2.0),
and Docker image `docker.io/pcvantol/technical-debt-engine:0.2.0`. The Docker
OCI index is `sha256:8285a5082eaa1a5ac914b349ddec21c9e02cc4269421774d4f112383bc688ca9`;
no `latest` tag exists. See the [Runtime Qualification Report](RUNTIME_QUALIFICATION_REPORT_0.2.0.md)
for the immutable publication evidence and public-runtime validation.
TDE 1.0.5 completed the consumer-driven DJConnect enablement program. The
explicitly authorized TDE 1.1 increment adds cross-language primary-product
complexity parity without creating a new capability or changing Observe-only
governance. See the [roadmap](PRODUCT_ROADMAP.md) and [active
backlog](PRODUCT_BACKLOG.md).

Release `1.0.5` is the current public baseline. TDE `1.1.0` is not a consumer
pin until its public-wheel and cross-platform qualification has completed.

## Product contracts

Consumers integrate only through the public `tde` CLI, configuration, evidence
schema, exit codes, and stable released contracts—not runtime internals. See
[INTEGRATION_MODEL.md](INTEGRATION_MODEL.md).

The `complexity` capability discovers the dominant canonical product language:
Python uses Radon; JavaScript/TypeScript, Swift, C/C++ and C# use Lizard. All
five normalize to `complexity.cyclomatic.product.maximum` and the same policy.
See the [complexity support matrix](docs/complexity-support-matrix.md).

Operational repository assurance is available through `tde assure`; see [SOFTWARE_ASSURANCE.md](SOFTWARE_ASSURANCE.md) for its canonical evidence and candidate-artifact verification contract.

## Documentation
Expand All @@ -34,6 +34,8 @@ Operational repository assurance is available through `tde assure`; see [SOFTWAR
- [Capability model](CAPABILITY_MODEL.md)
- [CLI specification](CLI_SPECIFICATION.md)
- [Code Size Runtime contract](CODE_SIZE_RUNTIME.md)
- [Cross-language complexity support](docs/complexity-support-matrix.md) and
[ADR-0065](architecture/adr/ADR-0065-cross-language-complexity-policy-parity.md)
- [Evidence schema](EVIDENCE_SCHEMA.md)
- [Qualification model](QUALIFICATION_MODEL.md)
- [Roadmap](PRODUCT_ROADMAP.md) and [backlog](PRODUCT_BACKLOG.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# ADR-0065: Cross-language complexity policy parity

## Status

Accepted for the TDE 1.1 implementation increment.

## Context

TDE 1.0.5 publishes one canonical `complexity` capability, but its only
adapter is Radon and therefore only Python product source receives meaningful
complexity evidence. The seven selected DJConnect source consumers use Python,
TypeScript/JavaScript, Swift, C/C++, and C#. Auxiliary Python files must not
substitute for a repository's primary product language.

The existing policy already evaluates the normalized product metric
`complexity.cyclomatic.product.maximum` with warning `15` and blocking `30`.
Those thresholds remain unchanged.

## Decision

TDE 1.1 retains the single `complexity` capability, policy route, assessment
profile and qualification route. It adds registered language adapters, not
language-specific capabilities or policies.

| Product language | Adapter | Analyzer and pin | Platforms | Native output |
| --- | --- | --- | --- | --- |
| Python | `complexity.radon` | `radon==6.0.1` | Linux, macOS, Windows | JSON |
| TypeScript / JavaScript | `complexity.lizard` | `lizard==1.23.0` | Linux, macOS, Windows | CSV |
| Swift | `complexity.lizard` | `lizard==1.23.0` | macOS (also portable Python environments) | CSV |
| C / C++ | `complexity.lizard` | `lizard==1.23.0` | Linux, macOS, Windows | CSV |
| C# | `complexity.lizard` | `lizard==1.23.0` | Linux, macOS, Windows | CSV |

Both analyzers are public Python packages and are exact runtime dependencies.
Radon is retained for Python because its structured Python analysis is the
existing public contract. Lizard is MIT licensed, publicly installable,
version-pinnable and documents function-level CCN, locations, deterministic
single-thread CLI operation, and support for all four added language families.

The adapters normalize every emitted symbol to the existing canonical shape:
repository-relative path, language, symbol name and kind, location, CCN,
product-source classification, adapter and analyzer provenance. Raw analyzer
formats never reach policy evaluation. Each adapter result records executable,
package identity, analyzer version, language, host platform and a stable raw
output digest.

`primaryLanguage` is discovered generically from canonical product-source
files: the recognised language with the highest nonblank source-line count.
Ties are retained as multiple primary languages. The product policy summary is
computed from symbols in those primary languages only. Non-primary symbols
remain symbol-, file-, language- and repository-level evidence, but cannot
satisfy a missing primary-language measurement. This prevents a Windows Python
helper from qualifying C# complexity, without repository-name logic.

One shared source-classification model identifies product, test, fixture,
mock, generated, dependency/vendor, build/cache, verification and coverage
artifact paths. Generated coverage XML/JSON/HTML/intermediates are excluded
from both Code Size discovery and Complexity adapter input while remaining
available to the Coverage capability's configured artifact reader.

Availability is explicit. No applicable product source is valid evidence with
no numeric product metric; unavailable analyzers, unsupported versions,
execution failures, malformed output, empty output for applicable source,
missing locations, partial language analysis, and duplicate symbols are
fail-closed structured limitations. They never become a zero metric or an
implicit PASS.

## Rejected alternatives

- **A new capability per language:** would fork policy, qualification and
evidence semantics, contrary to the public TDE contract.
- **Consumer-local analyzers or policies:** would make evidence nonportable and
let consumers bypass the exact public runtime.
- **SwiftLint plus language-specific tools:** SwiftLint's cyclomatic rule is a
lint violation mechanism rather than a complete, stable symbol metric feed;
separate toolchains also multiply release and platform qualifications.
- **A TDE parser/CCN algorithm:** forbidden without a separate architectural
decision; public analyzers already meet the required capability.
- **Let any supported-language result qualify a repository:** auxiliary scripts
could hide missing primary product coverage.

## Consequences

Raw CCN values remain analyzer-dependent and should not be interpreted as
mathematically interchangeable across languages. They are intentionally
evaluated through one transparent product policy after canonical normalization.
Existing Python/Radon evidence remains valid: TDE 1.1 adds optional provenance
and language summaries without changing the established metric keys or policy
thresholds. Consumers continue to use only the published `tde` CLI and remain
Observe-only.
7 changes: 7 additions & 0 deletions docs/assessment-profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ build caches.
Local tooling and compilation output are not repository source code and cannot
affect policy measurements.

Complexity uses the same canonical classification. It discovers the primary
product language by recognised product-source lines, measures it through a
registered public analyzer, and never lets auxiliary scripts in another
language substitute for it. Coverage XML/JSON/HTML/intermediate output is
excluded from Code Size and Complexity discovery but remains available to the
Coverage capability.

Profiles are JSON documents with an identifier, version, description,
capability entries, a policy file and metadata. Each capability selects exactly
one of `required` or `optional`.
Expand Down
6 changes: 6 additions & 0 deletions docs/assessment-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ Compatibility is defined as follows:
The Runtime validates every emitted capability, policy, decision, and assessment
envelope before persistence. An incompatible or malformed schema is rejected
fail-closed.

TDE 1.1 preserves schema compatibility: cross-language complexity provenance is
additive adapter evidence. Existing Radon Python metrics and metric keys remain
valid; multi-language adapter identity, package/executable and platform fields
are carried in the existing `adapterResults` contract rather than a
language-specific top-level schema.
29 changes: 29 additions & 0 deletions docs/complexity-support-matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Complexity support matrix

TDE 1.1 exposes one public `complexity` capability. Adapter selection is
repository-discovery-driven; consumers never invoke an adapter themselves.

| Language | Adapter | Analyzer | Pin | CI support | Evidence |
| --- | --- | --- | --- | --- | --- |
| Python | `complexity.radon` | Radon | `6.0.1` | Linux, macOS, Windows | canonical, qualified |
| JavaScript | `complexity.lizard` | Lizard | `1.23.0` | Linux, macOS, Windows | canonical, qualified |
| TypeScript | `complexity.lizard` | Lizard | `1.23.0` | Linux, macOS, Windows | canonical, qualified |
| Swift | `complexity.lizard` | Lizard | `1.23.0` | macOS | canonical, qualified |
| C / C++ | `complexity.lizard` | Lizard | `1.23.0` | Linux, macOS, Windows | canonical, qualified |
| C# | `complexity.lizard` | Lizard | `1.23.0` | Linux, macOS, Windows | canonical, qualified |

Lizard is selected because its public CLI emits deterministic CSV with
function-level CCN and source locations, and supports every non-Python language
in the selected DJConnect set. TDE invokes it single-threaded against an
explicit, classified source list. Radon remains the Python adapter.

The shared policy evaluates only primary product languages through
`complexity.cyclomatic.product.maximum` (warning `15`, blocking `30`). Test,
fixture, mock, generated, dependency, build, coverage and verification symbols
remain either excluded from discovery or separately classified; they cannot
inflate the primary product result.

The adapter evidence includes analyzer executable, installed package identity,
version, adapter identity/version, language, platform, raw-output hash and
run-local timestamp through the enclosing assessment. Analyzer unavailability
and invalid evidence are structured fail-closed results, never zeroes.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"

[project]
name = "technical-debt-engine-runtime"
version = "1.0.5"
version = "1.1.0"
description = "Technical Debt Engine runtime foundation API"
requires-python = ">=3.11"
dependencies = ["radon==6.0.1"]
dependencies = ["lizard==1.23.0", "radon==6.0.1"]

[project.scripts]
tde = "tde_cli.main:console_main"
Expand Down
2 changes: 1 addition & 1 deletion src/tde_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from tde_runtime.differential import AssessmentBaselineRegistry, DifferentialEngine, DifferentialError


CLI_VERSION = "1.0.5"
CLI_VERSION = "1.1.0"
GENERATION = "1"


Expand Down
12 changes: 12 additions & 0 deletions src/tde_runtime/analyzer_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
import re
import shutil
import subprocess
import sys
from pathlib import Path
from typing import Any


def discover(executable_name: str, minimum_version: tuple[int, int], timeout: int) -> dict[str, Any]:
executable = shutil.which(executable_name)
# A public wheel installs analyzer console scripts into the active Python
# environment. Invoking `tde` by absolute path does not necessarily prepend
# that environment's bin/Scripts directory to PATH, so discover the sibling
# script deterministically before declaring a bundled dependency missing.
if not executable:
# `sys.executable` can be a symlink to a base interpreter in a virtual
# environment; `sys.prefix` remains the active environment identity.
directories = (Path(sys.prefix) / ("Scripts" if sys.platform == "win32" else "bin"), Path(sys.executable).parent)
candidates = tuple(candidate for directory in directories for candidate in (directory / executable_name, directory / f"{executable_name}.exe"))
executable = next((str(candidate) for candidate in candidates if candidate.is_file()), None)
if not executable:
return {"status": "ANALYZER_NOT_FOUND", "limitation": {"id": f"analyzer.{executable_name}.unavailable", "description": f"{executable_name} is not on PATH.", "cause": "analyzer unavailable"}}
try:
Expand Down
Loading