atif-sql · Tech debt
Section titled “atif-sql · Tech debt”There are zero TODO, FIXME, HACK, and XXX markers in this repository. Three
scans confirm it: over packages/*/src, over packages/ plus scripts/, and over every
file git ls-files names. That means the marker channel carries no signal here. It does
not mean the codebase is debt-free, and this page exists because the debt is real and
lives elsewhere.
So the register below is assembled from five sources rather than from comments. Every citation on this page carries its full path, so no reference resolves through a nearby antecedent.
- The suppression config, read as the debt register someone already wrote.
select = ["ALL"]with exactly 12 ignores (pyproject.toml:153-184), four pyright rules switched off (pyproject.toml:668-679), ty atall = "error"with no rule disabled (pyproject.toml:370-371), and per-site# noqa/# pyright: ignorecounts taken by grep. Almost every config entry carries its own measured count and its cost-of-removal analysis inline, which is a better debt record than a comment marker and is quoted here rather than re-derived. - Version ceilings and the reason attached to each, read at the pin in the member manifests, not inferred from the lockfile.
- Install weight and platform coverage, computed independently from
uv.lockby walking theatif-sqldependency graph twice — once whole, once withharborblocked — following extras as well as direct dependencies. - Asymmetric enforcement between sibling surfaces: a coverage floor enforced in CI but not in the declared definition of done, so a local green run does not measure it.
- Coverage and test-shape gaps, per module. Coverage figures are measured from the generated report, which is gitignored, so every figure is cited to the source module it describes.
Category and cost vocabularies are closed. Categories: marker, wrong abstraction,
error handling, dead code adjacent, deprecated pattern, version pin, duplicated logic, missing tests. Cost: S, M, L. No row carries the marker category, for
the reason in the first paragraph. Rank is cost-to-fix × consequence-of-leaving, so a
cheap fix for a harmless problem sinks and an expensive fix for a structural problem
rises.
Ranked register
Section titled “Ranked register”| Rank | Debt item | Category | Cost to fix | Citation |
|---|---|---|---|---|
| 1 | The entire Claude Code → ATIF conversion path runs through one PRIVATE upstream method, ClaudeCode._convert_events_to_trajectory, verified against harbor 0.22.0 only — so the manifest carries a minor-version ceiling and the unit tests are the drift alarm. Nothing upstream promises the method exists in 0.23. |
version pin |
L | packages/atif-converter/pyproject.toml:19-23 |
| 2 | Seven upstream conversion losses are catalogued as FidelityGap enum members rather than fixed. Gap 3 flattens the parentUuid tree by timestamp sort, losing branch and rewind structure; gap 7 drops the event uuid, making step-to-raw-record identity unrecoverable from the trajectory — recovered out of band through a parallel edges.jsonl sidecar the corpus layout mandates. |
wrong abstraction |
L | packages/atif-converter/src/atif_converter/domain/fidelity.py:44-79, docs/CONTRACT.md:26-28 |
| 3 | 63 of the 113 runtime distributions reach this project only through harbor — fastapi, uvicorn, starlette, the whole supabase client stack, litellm, openai, tiktoken, tokenizers, huggingface-hub, cryptography, aiohttp — for exactly one private method call. A CLI that converts JSONL ships a web server and a database client. 57% of the roster, 155 MiB. |
version pin |
L | RELEASING.md:215-222 |
| 4 | 415 pyright findings sit behind three disabled Unknown-propagation rules, and the config names the fix it has not built: a TypedDict model of the ~/.claude JSONL record and the ATIF trajectory would close 144 of them. Until that model exists, every JSON-shaped value in the hottest modules is dict[str, Any] narrowed by isinstance, with the type checker’s opinion switched off. The two heaviest concentrations are the converter’s enrichment module at 59 findings and the analytics corpus reader at 33. |
wrong abstraction |
L | pyproject.toml:641-671 |
| 5 | 15 SQL statements are built by string interpolation through a hand-rolled quote-doubling escape, because DuckDB rejects prepared parameters as table-function arguments. ruff’s # noqa: S608 silences ruff only — bandit reports the same 15 as B608 and those findings upload to code scanning, so the suppression is not portable across the two scanners that both implement the rule. |
deprecated pattern |
L | pyproject.toml:737-739, packages/atif-duck/src/atif_duck/infrastructure/registry.py:172, packages/atif-embed/src/atif_embed/infrastructure/corpus_text_rows.py:108 |
| 6 | No test reads a real ~/.claude corpus. The whole integration tier is two tests over two synthetic 4-event sessions, and parity oracles against the predecessor implementation are explicitly not part of this repo. The seven fidelity gaps are policy about real-world JSONL shapes that nothing real-world exercises. |
missing tests |
L | packages/atif-cli/tests/test_integration.py:3-9, packages/atif-cli/tests/test_integration.py:24-34, AGENTS.md:92-94 |
| 7 | hdbscan 0.8.44 has never published an aarch64 wheel, so a first install on Graviton, an ARM CI runner, or a linux/arm64 container compiles five Cython extensions and needs a C toolchain. musl is not merely slow but impossible: lancedb 0.37.1 publishes no sdist at all, so there is nothing to build from. |
version pin |
L | RELEASING.md:203-213 |
| 8 | The four size ratchets and the complexity ratchet are set at the measured worst function in the tree — max-statements = 119 for _friction_async, max-complexity = 38 for enrich_trajectory, max-args = 19 for the search command. The ratchet stops growth and permanently blesses the current outliers; nothing in the config plans their reduction. |
wrong abstraction |
L | pyproject.toml:258-281, packages/atif-analytics/src/atif_analytics/application/use_cases/friction.py:240, packages/atif-converter/src/atif_converter/domain/enrichment.py:198 |
| 9 | TC001/TC002/TC003 are ignored on the strength of a manual probe: moving 58 imports under TYPE_CHECKING broke typing.get_type_hints on 159 first-party functions and classes. The 182-site PLC0415 ignore beside it has a regression test proving its property in a fresh interpreter; the get_type_hints property has none, so the argument that justifies the ignore is not locked. |
missing tests |
M | pyproject.toml:170-183, packages/atif-cli/tests/test_lean_import.py:35 |
| 10 | Every one of the nine security scanners has its findings exit code swallowed at eight sites, by a stated contract: findings do not fail the job, only a scanner that produced no usable report does. Gating is delegated entirely to GitHub code-scanning alerts and branch protection, so nothing inside the repo fails on a new vulnerability. | error handling |
M | mise.toml:217-223, mise.toml:366, mise.toml:482 |
| 11 | The provider/dimension guard exists as two deliberate 83-line twins because the independence contract forbids either package importing the other. The drift pin reads the atif-duck twin as SOURCE TEXT, parses it with ast, and asserts substrings — including a raw source.index("raise EmbeddingProviderMismatch") that silently changes meaning if the raise site is renamed or a second raise appears. The two docstrings have already diverged; the pin covers the recovery string and the interpolation, not the rule. |
duplicated logic |
M | packages/atif-embed/tests/test_guard_twin_pin.py:3-13, packages/atif-embed/tests/test_guard_twin_pin.py:93-95, packages/atif-duck/src/atif_duck/domain/embedding_guard.py:5-16 |
| 12 | The clustering path is the least-tested code in the tree and it is also the least portable: the structural clustering module at 22% (23 of 30 lines unexecuted), the Lance reader at 31%, the cluster use case at 51% — against an 89.98% whole-tree combined figure. This is exactly the UMAP/HDBSCAN code behind the aarch64 wheel gap. | missing tests |
M | packages/atif-analytics/src/atif_analytics/domain/structure/cluster.py:88, packages/atif-analytics/src/atif_analytics/infrastructure/lance_reader.py:38-49, packages/atif-analytics/src/atif_analytics/application/use_cases/cluster.py:50 |
| 13 | Both binding contract documents disclaim describing the code. CONTRACT-V2 states outright that when it disagrees with the code, the code wins and the file is design intent “not a description of current behavior”; CONTRACT v1 calls its own scope section historical. A binding document that pre-emptively surrenders authority cannot be used to detect drift, which is the only thing a contract document is for. judgment-call — the disclaimers are honest, and honesty about staleness is still staleness. | dead code adjacent |
M | docs/CONTRACT-V2.md:3-8, docs/CONTRACT.md:5-8 |
| 14 | One version constraint is unexplained where every other pin in the repo justifies itself: lancedb>=0.30,<0.38 is declared twice, in two members, with no comment on either side. A single distribution declares one constraint per package, so test_distribution.py now fails on two members that disagree — but it cannot ask why a constraint exists, which is what a comment is for. |
version pin |
S | packages/atif-analytics/pyproject.toml:27, packages/atif-embed/pyproject.toml:20-22 |
| 15 | FakeConverter — a scriptable test double — ships inside the installable atif-corpus wheel under infrastructure/, and it is the converter the end-to-end materialize suite runs against. A fake that both mutates and reads corpus state stands in for the real harbor adapter in exactly the tests that would catch a state-transition bug. |
wrong abstraction |
S | packages/atif-corpus/src/atif_corpus/infrastructure/fake_converter.py:3-9, packages/atif-corpus/tests/test_materialize.py:25 |
| 16 | Three independently declared DomainError(Exception) bases with the same name and no shared ancestor, so a caller composing two members cannot write one except clause and any symbol-name search cross-attributes all three. |
duplicated logic |
S | packages/atif-converter/src/atif_converter/domain/errors.py:14, packages/atif-embed/src/atif_embed/domain/errors.py:14, packages/atif-models/src/atif_models/domain/ports.py:39 |
| 17 | The 89% coverage floor is not part of the declared definition of done. mise run check depends on nine gates and test:cov is not among them, so a local green run can drop coverage below the floor and only the CI job notices. |
missing tests |
S | mise.toml:197-212, pyproject.toml:560, .github/workflows/check.yml:78 |
Explicit markers
Section titled “Explicit markers”None. This section is empty because the repository contains no comment markers, not because the search was narrow.
- Scanned
packages/*/srcfor\bTODO\b,\bFIXME\b,\bHACK\b,\bXXX\b: 0 matches. - Scanned
packages/plusscripts/with the same pattern: 0 matches. - Scanned every file
git ls-filesreports: 0 matches. - No
@deprecateddecorator and no# DEPRECATEDbanner sits on any first-party symbol. Everydeprecat*hit in the tree describes an UPSTREAM deprecation, and the two members reading the LanceDB store name the same one independently —db.table_names()atpackages/atif-embed/src/atif_embed/infrastructure/lance_store.py:90and atpackages/atif-analytics/src/atif_analytics/infrastructure/lance_reader.py:43, because the independence contract means neither can read the other’s warning. The other two are a lancedb kwarg family atpackages/atif-embed/src/atif_embed/infrastructure/lance_store.py:274and an osv-scanner flag atmise.toml:362. - The closest thing to a marker is
RELEASING.md:215, which names the harbor dependency subtree “the standing follow-up” in prose — a declined-scope note in the release record rather than a comment in code. It is register row 3.
The absence is enforced, not incidental. select = ["ALL"] at pyproject.toml:146 leaves
flake8-fixme and flake8-todos on, and neither appears among the 12 ignores at
pyproject.toml:153-184.
Probed 2026-08-28 by dropping one # TODO: ... comment into packages/atif-duck/src/:
ruff check exits 2 with TD002 (missing author), TD003 (missing issue link), and
FIX002 (line contains TODO). A marker cannot reach main past mise run lint, so the
debt lives in the five channels the register draws on instead of in markers. A sixth channel
exists and contributes no row: a comment explaining the code by reference to an
implementation no installer of this package can obtain. grep -riE 'claude-sql|predecessor' packages/*/src returns 0 lines. No lint can police that one, so it is empty by review
rather than by gate, which is why it is worth naming here.
Pattern-level smells
Section titled “Pattern-level smells”The toolchain config is the real debt register, and it is load-bearing
Section titled “The toolchain config is the real debt register, and it is load-bearing”Every suppression in pyproject.toml carries its measured count and its cost-of-removal
analysis, which makes the config the most honest debt document in the repo — and also
means a large amount of unresolved work is encoded as a rule that is off rather than as an
issue anyone tracks. The three disabled Unknown-propagation rules cover 415 findings and
the config names the two things that would let them back on, neither of which exists.
Three TC* rules are off because a probe found that fixing them breaks
typing.get_type_hints on 159 first-party functions. Nine per-site # noqa: N818 mark
error classes deliberately not named *Error. Five size limits are pinned at the current
worst function. Reading the config top to bottom is a more complete account of what this
codebase owes than reading its comments, and none of it appears in any tracker.
Shows up in:
pyproject.toml:153-184— the 12 ignores, each with its site count.pyproject.toml:641-680— 415 findings traced to origin, plus the 23-warning stub gap.pyproject.toml:258-281— the five ratchets set at the measured worst.pyproject.toml:370-371—[tool.ty.rules] all = "error"with nothing disabled beneath it, which is what the pattern looks like when it holds: a suppression here would need the same measured argument every entry above carries.
Cost: L — the analysis is done and written; the work it defers is a TypedDict model of
the JSONL record, four stub distributions, and three refactors of named functions.
One private upstream method carries the whole product
Section titled “One private upstream method carries the whole product”atif-converter exists to call ClaudeCode._convert_events_to_trajectory, a private
harbor method. Four consequences compound. The manifest carries a minor-version ceiling
that only a manual re-audit can lift. Seven data losses are documented as enum members
because the private method’s behavior cannot be changed, and two of them — flattened
parent chains, dropped event uuids — are worked around by writing a parallel edges.jsonl
sidecar for every session, so the corpus layout itself is shaped by an upstream defect.
The dependency arrives with 63 other distributions including a web framework, an ASGI
server, and a hosted-database client, none of which this code imports.
And it forecloses a supply-chain control the rest of the toolchain would take. semgrep’s
uv-missing-dependency-cooldown asks for exclude-newer under [tool.uv], so a freshly
published version waits before it can be resolved — the standard mitigation for a
compromised release. Probed 2026-08-28 with uv lock --dry-run --exclude-newer "7 days":
the workspace becomes UNSATISFIABLE, because no distribution inside
harbor>=0.22.0,<0.23 is older than the cutoff. The control is declined for that measured
reason rather than overlooked, and uv.lock plus uv sync --locked remain what actually
pins the resolution.
Shows up in:
packages/atif-converter/pyproject.toml:19-23— the ceiling and the reason.packages/atif-converter/src/atif_converter/domain/fidelity.py:44-79— the seven gaps.docs/CONTRACT.md:26-28—edges.jsonl, the sidecar that exists because of gaps 3 and 7.RELEASING.md:215-222— 63 of 113 packages, 155 MiB, for one method.
Cost: L — either vendor the conversion the method performs and drop harbor entirely, or get a public entry point upstreamed. Both are real projects.
The independence contract is paid for in copies, and the copies are pinned by text
Section titled “The independence contract is paid for in copies, and the copies are pinned by text”Five packages may never import each other, so shared logic is duplicated instead of
extracted. Three byte-identical SQL-literal escapers exist, one per package that inlines
SQL, and the same pure provider/dimension guard exists as two 83-line twins. The escapers
are the contract’s price paid honestly: each package owns one copy, in domain/, and no
import would be legal. The guard is the price paid dangerously. The mechanism keeping the
twins honest is a test that reads the other package’s file as text, parses it with ast,
and asserts substrings — including one raw str.index on a raise keyword. That test is
fragile in a way an import never is: it passes when the twins agree on a string and
disagree on their logic, and it breaks on a rename that changes nothing.
Shows up in:
packages/atif-duck/src/atif_duck/domain/sql_literal.py:18andpackages/atif-embed/src/atif_embed/domain/sql_literal.py:24— two of the three escapers, each in its own package’sdomain/, each reached by that package’s adapters.packages/atif-cli/src/atif_cli/app.py:106— the third, in the composition root, which could legally import either of the two above and does not.packages/atif-embed/tests/test_guard_twin_pin.py:93-95— the substring assertions that stand in for a shared import.packages/atif-duck/src/atif_duck/domain/embedding_guard.py:5-16— the twin whose docstring has already drifted from its counterpart’s.
Cost: M — collapsing the guard twins needs a decision about a shared-kernel package the contract forbids. The three escapers need no decision: a shared kernel would absorb them, and short of one, one copy per package is the contract working rather than failing.
Findings never fail anything
Section titled “Findings never fail anything”Nine security scanners run, and every one has its findings exit code swallowed — eight
sites use a trailing || true, the rest an equivalent flag — under an explicit contract: a
finding does not fail the task, a missing report does. The reasoning is sound, because a
non-zero exit kills the CI step before the SARIF upload. The consequence is that no gate
inside this repository fails on a new
vulnerability, a new secret, or a new SAST finding, and enforcement lives entirely in
GitHub code-scanning alerts and branch protection. The same asymmetry appears in the
coverage floor: fail_under = 89 exists, and the task that reads it is not among the nine
mise run check depends on, so the declared definition of done does not measure coverage.
The suppression ledger this tier generates is currently empty, which reads identically to
“nothing needed suppressing” and to “nobody has looked”.
Shows up in:
mise.toml:217-223— the contract, stated plainly.mise.toml:366andmise.toml:482— two of the eight swallow sites, one of them bandit’s, whose 15 B608 findings therefore reach code scanning permanently.mise.toml:197-212— the nine gates, withouttest:cov.pyproject.toml:560— the floor that only.github/workflows/check.yml:78enforces.
Cost: M — splitting each scanner into “run and upload” plus “assert the finding delta against a baseline” is mechanical; agreeing on the baseline is the work.
The code the type checkers guard hardest is the code the tests reach least
Section titled “The code the type checkers guard hardest is the code the tests reach least”Combined line-and-branch coverage is 89.98% and the misses are not spread evenly — they
concentrate in one path, the numeric clustering one.
packages/atif-analytics/src/atif_analytics/domain/structure/cluster.py:88 is at 22%, and
it is the module carrying a pyright: ignore on the UMAP call and depending on the one
package with no aarch64 wheel.
packages/atif-analytics/src/atif_analytics/infrastructure/lance_reader.py:38-49 is at 31%,
so the store-shape branches deciding whether the structural stages run at all are
unexecuted. Above all of it, the end-to-end materialize suite runs against a fake converter
that ships in the wheel, so the state transitions that matter most are exercised against a
double.
Shows up in:
packages/atif-analytics/src/atif_analytics/domain/structure/cluster.py:88— 22% covered, and the site of the UMAPpyright: ignore.packages/atif-analytics/src/atif_analytics/infrastructure/lance_reader.py:38-49— 31% covered, including thenoqa: BLE001that turns any store-shape surprise into a skip.packages/atif-corpus/src/atif_corpus/infrastructure/fake_converter.py:3-9— the double the materialize suite uses instead of the real adapter.packages/atif-cli/tests/test_integration.py:3-9— the whole integration tier: two synthetic 4-event sessions.
Cost: M — a corpus fixture built from real, scrubbed ~/.claude records is the whole of
it, and it is what would exercise both the clustering path and the fidelity gaps nothing
real-world currently touches.
See also
Section titled “See also”- impact analysis — 24 shared source citations
- contract map — 19 shared source citations
- module map — 18 shared source citations
- processes — 16 shared source citations
- business logic — 14 shared source citations