docs/hesitations.md
Hesitations
Every moment while using the product where I stopped, doubted, or could not proceed. Each carries a reproduction. Findings here outrank tests: the two worst defects this project has shipped were both found by opening an unfamiliar repository, and neither would have been reached by reasoning.
Truth failures are repaired immediately. Inconveniences are recorded and left.
Repaired
H1 — "refusals: none" on a repository with 134 imports · TRUTH
ky reported nothing refused. Two causes, compounding:
.jsspecifiers were not resolved. TypeScript's NodeNext convention writes the emitted extension, so correct TS imports./x.jswherex.tsexists. Zero imports were extracted — no wrong answer, no answer.- The refusal was conditional on
imports.length > 0. A refusal is a claim about what the vocabulary can hold, true whether a run saw five hundred instances or none. Conditional on the count, "we found none" and "we cannot represent these" both rendered as silence.
A refusal that disappears when extraction fails is the failure hiding its own
evidence. Repro: acquireRepositoryWorld on any NodeNext TS repo; expect a
non-zero import dependency refusal.
H2 — date-fns could not be opened at all · TRUTH
RangeError: Maximum call stack size exceeded, 1631 source files.
Math.max(...xs) passes every element as a separate argument and throws past
~10⁴–10⁵. coChange builds up to n²/2 pairs, so the spread blew the stack
before a single building existed. Ten sites across src/; symmetrise spread
the entire distance matrix.
Repaired with lib/world/fold.ts and guarded by a test forbidding the pattern
anywhere in src/ — which immediately found an eleventh site in
adapters/repo-scene.ts that manual search had missed. Repro:
tests/changeset.test.ts, 200 000 elements.
H3 — position claims finer than the frame's own error · TRUTH
date-fns aligns to a residual of 38.33 while MOTION_FLOOR is 3, so every
position mark there was noise wearing a number: "moved 4.2 units" inside a
frame uncertain by 38.
You cannot see motion smaller than your measurement error. Position marks
now require moved > max(floor, frame.residual). Effect on date-fns: subjects
offered for review fell 1605 → 303, with 1302 moving to display-only.
H4 — a ring I could see and could not reach · INTERACTION
The interface honestly said Review skips display-only subjects, and I immediately wanted to inspect one. Honest, and still a dead end. Added a second walk — "Inspecting display-only differences" — deliberately disjoint from Review rather than appended to it.
H9 — the build gate failed on an unreproducible measurement · INSTRUMENT
IV.2: composition stays linear failed the full suite repeatedly while passing
every time it ran alone. node --test runs files concurrently, so contention
can starve one scale and not the other and the ratio spikes for reasons
unrelated to composition. Raising samples 5 → 9 reduced it and did not remove
it.
Repaired by applying the project's own rule to its own instrument: a finding must reproduce before it is reported. An exceedance is now measured a second time and only a repeat fails. The threshold is unchanged, both observations are printed, and a real quadratic regression (2.78 against a 2.2 threshold) reproduces every time.
H5 — a large repository took 57 s to open · PERFORMANCE
Profiled rather than guessed. Two costs, both removed without changing a single output value:
| phase | before | after | cause |
|---|---|---|---|
| import extraction | 15.9 s | 0.06 s | one git show per file; the question was always "which lines import relatively", never "what is in this file" — one git grep answers it |
couplingMatrix |
35.2 s | ~1 s | Floyd–Warshall over a Map of Maps: two hash lookups in the innermost statement of a 4.3e9-iteration loop, now a flat Float64Array |
| repo | before | after |
|---|---|---|
| ky | 539 ms | 55 ms |
| zustand | 499 ms | 42 ms |
| zod | 5 058 ms | 293 ms |
| date-fns | 57 s | 5.4 s |
Buildings, links, refusals and unplaced counts are identical on all six repositories — this bought speed and nothing else.
The density has a specific cause worth keeping: one date-fns commit touches 1606 files, and that single commit produces ~1.29 M co-change pairs on its own. The graph is dense because the history is.
Still open: n³ returns as a wall a few times larger, and the flat matrix is n² doubles — 21 MB at 1629 subjects, 800 MB at 10 000. Both ceilings are real and neither is guessed at.
H6 — zod reports 0 changes across 5 commits · RESOLVED, NOT A DEFECT
Confirmed by inspection: those six commits are chore:, docs: and ci: — they
touch zero source files. Reporting no repository change was correct.
Recorded as resolved rather than deleted, because "the system said nothing changed and was right" is the outcome a suspicion is supposed to be able to reach.
H8 — an omission nobody could see · TRUTH
Recorded as "reported but unreachable". It was worse: unplaced never left
acquisition. The API did not return it and no surface showed it, so a
repository with 8 source files rendered 7 buildings and said nothing about
the eighth. A reader counting buildings would conclude the eighth did not
exist.
Refusing to fabricate a position is only half of it. The other half is saying that you refused.
The refusal now lives on the World — so it survives serialisation — carrying
its basis and what is known:
lint-staged.config.ts — position is solved from co-change coupling, and this subject never changed in the same commit as another source file, so nothing licenses a position for it. known:
repo/bytes=146 · repo/commits-touching=1
Measured cause, verified on three repositories: every unplaced subject has
commits-touching = 1 and appears in no co-change edge. measured but unplaceable and unobserved are rendered differently, because a bare list
would collapse them. An empty array is a claim that nothing was withheld.
Found on myself. The standard test fixture contains m1/tall.ts, added
several sessions ago to hold the height reference steady. It appears in no
commit, so it has never been placed — every measurement taken with that fixture
ran against a world with a silently missing building, and nothing said so. The
omission was invisible to the person who introduced it. Now asserted, so it
cannot drift back into silence.
Recorded, not repaired
H7 — two counting units are correct and adjacent · AMBIGUITY
13 changed subjects and 25 recorded fact changes are different questions
with different answers. Both are labelled and their relationship is stated, and
a reader in a hurry may still read the second as a total of the first. No
measurement supports a fix yet.
H10 — the silent fourth state · TRUTH
Found by applying the standing rule rather than by hitting it: a path must be placed, refused, or unobserved, and there must be no fourth. Checking whether a fourth existed found that it did, and it was the largest omission in the product.
Paths not matching the connector's extension set were dropped at the tree scan. Counted, never mentioned:
| repo | in tree | entered the pipeline | dropped silently |
|---|---|---|---|
| ky | 68 | 53 | 15 |
| zod | 583 | 406 | 177 |
| date-fns | 1903 | 1631 | 272 |
| httpie (Python) | 265 | 0 | 265 |
The last row is the failure at full strength. httpie rendered 0 buildings
beside unplaced: [] — and by the semantics introduced hours earlier, an empty
refusal list is a claim that nothing was withheld. Two true statements
composing into a false one: this repository is empty. It has 133 Python files.
World.unobserved now carries the count, the vocabulary that was applied so the
omission is checkable, and a breakdown by extension so a reader can see what
kind of thing was skipped. Verified total on four repositories:
httpie tree 265 = placed 0 + refused 0 + unobserved 265 ✓
ky tree 68 = placed 53 + refused 0 + unobserved 15 ✓
zod tree 583 = placed 406 + refused 0 + unobserved 177 ✓
ms tree 23 = placed 7 + refused 1 + unobserved 15 ✓
H11 — a shallow clone fabricates a commit, and it moved the city · TRUTH
Found by the heuristic, not by an error: whenever you add a filter, ask where the excluded subjects go. Asking it of the history filter — rather than the path filter — found the worst defect of the session.
The boundary commit of a shallow clone has no parent, so git log --name-only
reports it as touching every file in the tree. On httpie,
2db28ef "docs: fix typo (#1548)" appeared to touch all 265 files.
Those pairs become co-change couplings, and couplings solve position. The city's layout was partly derived from a commit that never happened that way.
| shallow | full history | |
|---|---|---|
ky commits-touching max |
33 | 106 |
| ky links | 1006 | 673 |
More history produced fewer couplings — the inversion that gave it away.
Nothing can know what that commit really touched, so the file list is refused rather than guessed at, and the truncation is disclosed instead. The effect is large and it is the truth:
| repo | before | after |
|---|---|---|
| zustand | 49 buildings, 0 unplaced | 5 buildings, 45 unplaced |
| p-queue | 14 buildings | 13 buildings, 1 unplaced |
Zustand has 40 real commits and only 5 of its files genuinely co-change. The other 45 are now measured and honestly unplaceable, instead of positioned by a commit that did not touch them.
This invalidates earlier numbers in this file. Every fleet measurement above was taken on shallow clones, so link counts were inflated and commit counts were floors. The findings they supported still hold — they concerned attribution and scale, not absolute coupling — but the figures were measured through a window nobody had declared.
Method
- Build a visible capability.
- Use it on a repository the system has never seen.
- Stop the moment something feels wrong.
- Repair only what blocks truthful use; record the rest here.
- Repeat.
Repositories exercised so far: ky, p-queue, zod, zustand, ms,
date-fns.