These 18 findings from the 2026-07-23 technical-debt audit are deliberately not scheduled. Each is real and verified, but acting on any of them now would be speculative — each has a trigger that makes it worth doing, and until that trigger fires the cheapest correct action is to leave it alone.
This issue exists so they are not rediscovered by the next audit. It is a tracking parent and carries no Type label; convert an entry to its own issue when its trigger fires.
Waves 1 and 2 are in the Technical debt — 2026-07 audit milestone.
| # |
Finding |
Sev |
Effort |
Trigger |
F35 |
Jest runs in a CJS island with node10 resolution; production's ESM/node16 boundary is untested |
high |
L/m |
An ESM-only dependency becomes required, or an advisory lands against @actions/core 2.x / @actions/github 8.x. Not for testing index.ts — T1 solves that. Also unblocks F59's oracle |
F50 |
evaluateDiff still parses model JSON through any; a missing key gives no "the model never answered" signal |
low |
s/s |
Bundle into the next review-verdict.ts change |
F114 |
init bootstraps every new edition; ~436 of ~560 executable lines have no test entry point, at 23.7% branch |
med |
s/m |
Next time init.ts is opened for a behaviour change. Both entry points are already exported — the whole cost is the tmpdir harness |
F49 |
The empty-PR short-circuit is undocumented: a PR changing no markdown still emits review-verdict: PASS |
low |
t/t |
Bundle into the next review-verdict.ts change |
F23 |
The F107 localization defence and the --localize rule set are CLI-only; the Action's sync path sets no customInstructions |
med |
m/m |
The first merged sync PR that reverts a localized code cell or figure label (the F97 pattern). Pull into T2·3 if it fires sooner |
F14 |
Localization reaches the model only from init, and the one free-text slot is double-booked with forward's pinning |
low |
s/m |
After T5 lands and someone asks for a localized edition to stay localized through ongoing sync |
F25 |
Three incompatible "don't really do it" concepts; forward — the only command that force-pushes — has neither |
med |
s/m |
Before the next 40+ file drift-recovery wave |
F56 |
Section prompts re-send the same ~6.5K-token prefix uncached on every call |
low |
s/s |
When a bulk wave's input-token bill becomes worth an afternoon; measure first |
F62 |
No prompt-cache breakpoint on the static prefix — re-billed at full input price |
low |
s/s |
When a bulk wave's input-token bill becomes worth an afternoon; measure first |
F9 |
Two glossary loaders remain — deliberately different candidate sets, duplicated read/parse code |
low |
s/s |
Only if a third consumer appears. The two that exist differ deliberately — see §6 |
F96 |
All 7 npm advisories trace to one EOL devDependency chain; no baseline note records that |
low |
m/m |
The audit-baseline note rides in Wave 1 PR K; dependabot next quiet week; the ESLint 9 migration when a plugin drops .eslintrc support |
F34 |
ESLint 8 (EOL) + @typescript-eslint 6 is the sole source of all six high advisories |
low |
s/s |
The audit-baseline note rides in Wave 1 PR K; dependabot next quiet week; the ESLint 9 migration when a plugin drops .eslintrc support |
F101 |
No dependabot or renovate config — dependency drift has no automated discovery channel |
low |
t/t |
The audit-baseline note rides in Wave 1 PR K; dependabot next quiet week; the ESLint 9 migration when a plugin drops .eslintrc support |
F97 |
deploy-docs.yml runs an unpinned npm install -g mystmd in a job holding pages: write |
low |
t/t |
Bundle into the next CI edit; they are one line each |
F98 |
Zero of seven third-party action uses are SHA-pinned; each is 1-3 majors behind |
low |
t/t |
Bundle into the next CI edit; they are one line each |
F100 |
chalk is pinned at ^4 because of the CJS harness — load-bearing and undocumented |
low |
t/t |
Bundle into the next CI edit; they are one line each |
F73 |
The 2,100-LOC e2e eval harness has no type-check gate anywhere |
low |
t/t |
Next time the eval harness is run and fails at run time, or the next scripts/glossary edit |
F107 |
12,159 tracked LOC live in side trees every gate skips — including the hand-copied glossary formatter |
low |
s/m |
Next time the eval harness is run and fails at run time, or the next scripts/glossary edit |
Three worth reading before acting
F35 (Jest → ESM/Vitest) is the largest item in the audit, and its trigger matters: do it when an ESM-only dependency becomes required, or when an advisory lands against @actions/core 2.x / @actions/github 8.x. Not in order to test src/index.ts — that is what T1 (#169) solves, at a fraction of the cost.
F9 (two glossary loaders) should be acted on only if a third consumer appears. The two that exist differ deliberately: the CLI adds repo-local candidates because it runs inside a checkout; the Action does not, because it reaches the target repo over the API and uses glossary-path. Documented at docs/user/glossary.md:76-86. v0.23.0 already collapsed four loaders with three behaviours down to these two — unifying further would reintroduce CWD-relative lookup in the Action.
F100 (chalk pinned at ^4) is load-bearing, not stale: ^4 is the last CJS release and the ts-jest CJS harness requires it. That it is undocumented is the actual defect, and a one-line comment prevents a well-meaning upgrade.
From the technical-debt audit of 2026-07-23 (141 candidates adversarially verified, re-validated against v0.23.0, 139 live). Effort is stopgap / full — t≈0.5h, s≈3.5h, m≈11h, L≈28h.
These 18 findings from the 2026-07-23 technical-debt audit are deliberately not scheduled. Each is real and verified, but acting on any of them now would be speculative — each has a trigger that makes it worth doing, and until that trigger fires the cheapest correct action is to leave it alone.
This issue exists so they are not rediscovered by the next audit. It is a tracking parent and carries no Type label; convert an entry to its own issue when its trigger fires.
Waves 1 and 2 are in the Technical debt — 2026-07 audit milestone.
F35@actions/core2.x /@actions/github8.x. Not for testingindex.ts— T1 solves that. Also unblocksF59's oracleF50evaluateDiffstill parses model JSON throughany; a missing key gives no "the model never answered" signalreview-verdict.tschangeF114initbootstraps every new edition; ~436 of ~560 executable lines have no test entry point, at 23.7% branchinit.tsis opened for a behaviour change. Both entry points are already exported — the whole cost is the tmpdir harnessF49review-verdict: PASSreview-verdict.tschangeF23F107localization defence and the--localizerule set are CLI-only; the Action's sync path sets nocustomInstructionsF97pattern). Pull into T2·3 if it fires soonerF14init, and the one free-text slot is double-booked withforward's pinningF25forward— the only command that force-pushes — has neitherF56F62F9F96.eslintrcsupportF34@typescript-eslint6 is the sole source of all six high advisories.eslintrcsupportF101.eslintrcsupportF97deploy-docs.ymlruns an unpinnednpm install -g mystmdin a job holdingpages: writeF98F100chalkis pinned at^4because of the CJS harness — load-bearing and undocumentedF73scripts/glossaryeditF107scripts/glossaryeditThree worth reading before acting
F35(Jest → ESM/Vitest) is the largest item in the audit, and its trigger matters: do it when an ESM-only dependency becomes required, or when an advisory lands against@actions/core2.x /@actions/github8.x. Not in order to testsrc/index.ts— that is what T1 (#169) solves, at a fraction of the cost.F9(two glossary loaders) should be acted on only if a third consumer appears. The two that exist differ deliberately: the CLI adds repo-local candidates because it runs inside a checkout; the Action does not, because it reaches the target repo over the API and usesglossary-path. Documented atdocs/user/glossary.md:76-86. v0.23.0 already collapsed four loaders with three behaviours down to these two — unifying further would reintroduce CWD-relative lookup in the Action.F100(chalkpinned at^4) is load-bearing, not stale:^4is the last CJS release and the ts-jest CJS harness requires it. That it is undocumented is the actual defect, and a one-line comment prevents a well-meaning upgrade.From the technical-debt audit of 2026-07-23 (141 candidates adversarially verified, re-validated against v0.23.0, 139 live). Effort is stopgap / full — t≈0.5h, s≈3.5h, m≈11h, L≈28h.