Repository navigation
Commit 361e5f3
Part of #23182 (row 4)
Clause-②: no
This PR covers row 4 of #23182 only: `@objectstack/metadata-fs`,
`test/external-write-resync.test.ts`, 24.3 s in run `38217670691`. It
changes one test file and no production file. #23182 stays open for rows
1, 3, 5 and 6.
## Where the 24 s went
Per case at BASE `6f4c518b01` (vitest, ms): create/update/delete
6042–6169, exactly-once 6082–6124, unreadable directory 7030–7048,
ENOENT 5012–5018, close 6.
All of it was idle waiting, on two things:
- **The sweep's 2 s cadence.** The first case waited for three sweeps in
a row: create, then update, then delete. The cadence is
`RESYNC_INTERVAL_MS`, a private constant in `src/repository.ts` that no
option sets. Making it injectable would widen
`FileSystemRepositoryOptions`, a published production surface, so I did
not take that route.
- **Three fixed 5 s quiet windows** (`QUIET_WINDOW_MS`), in the
exactly-once, unreadable-directory and ENOENT cases.
## What changed (test only)
- **One recovery still waits for the clock.** In the first case, the
scheduled sweep recovers the lost create with nobody calling anything.
The deadline is `RECOVERY_WAIT_MS` (15 s, unchanged). The case now also
requires the chain to re-arm after that sweep: `resyncTimer` must be set
again. This keeps the half of the pin that says the backstop runs by
itself and keeps running.
- **Every other sweep is called directly.** The update and delete
recoveries, and every quiet window, `await` the private `resync()`, the
same body the timer runs. A quiet window is now `QUIET_SWEEPS = 3`
sweeps, where the old window was sized at "comfortably more than two
sweeps". `self-write-suppression.test.ts` and
`external-delete-requires-absence.test.ts` already test this package
this way. The watcher stays blinded exactly as before, so a recovered
event can only come from a sweep.
- **Two cases are stricter.** In the unreadable-directory case, the
first sweep that meets the fault must report it. In the ENOENT case,
every driven sweep must hit the injected ENOENT (`enoentServed`). Before
this change, the ENOENT case passed even if no sweep ran.
- The fixed 200 ms sleep after `put()` in the unreadable-directory case
is gone. `put()` is awaited and sets the head in the same continuation.
- `RECOVERY_WAIT_MS` and `CASE_TIMEOUT_MS` are unchanged. No case was
deleted, skipped or moved.
## Wall time
Vitest module line, in ms, on a shared 4-core box under
`os-verify-lock`:
| | BASE `6f4c518b01` | AFTER `43fef097df` |
|:--|:--|:--|
| file alone | 24228 / 24364 (a verbose run: tests 24.18 s) | 3331 /
3303 / 3356 |
| package suite, `--maxWorkers=2` | 24226 / 24229 | 3387 / 3330 |
| package suite, `--maxWorkers=8` (2x oversubscribed) | NOT MEASURED |
3348 |
- **Per case AFTER:** about 2055 ms for create/update/delete (the one
scheduled sweep), about 1150 ms for exactly-once (the live watcher's 1 s
poll), and under 110 ms for each of the other three.
- **Package suite:** 11 files and 74 tests pass, before and after. The
suite's summed test time fell from 34.6 s to 13.8 s.
- **CI after this change:** NOT MEASURED here. This PR's own Test Core
log will carry the module line.
- `origin/main` (`afbf960c26`, which touches nothing in this package)
was merged before the AFTER readings.
## Ablation: every case can still fail
Each leg changed `src/repository.ts` through
`scripts/ablation-replace.mjs`: the anchor count went from 1 to 0, and
the marker was on disk. Each leg then ran the new file and a temporary
copy of the BASE file in one vitest run. Afterwards, the file was
restored to the HEAD blob `f76f6dee4f48`, with `git diff HEAD` empty.
The test imports `../src/index.js`, so no dist is involved.
| leg | mutation | red cases, this PR | red cases, BASE |
|:--|:--|:--|:--|
| A1 | `resync()` returns at once | 1, 3, 4 | 1, 3 |
| A2 | `scheduleResync()` never arms | 1 | 1, 3 |
| A3 | the chain never re-arms | 1 (re-arm assertion) | 1 (update) |
| A4 | the sweep forgets `heads` before each file | 1, 2 | 1, 2 |
| A5 | the fault latch is removed | 3 (3 reports) | 3 (3 reports) |
| A6 | an unreadable type is not recorded | none | none |
| A8 | A6, plus the delete pass's `existsSync` re-check removed | 3 (2
deletes) | 3 (2 deletes) |
| A7 | ENOENT is reported as a fault | 4 | 4 |
- **A2 is the one place where this PR reds fewer cases.** At BASE, the
unreadable-directory case also needed the scheduler. Now only case 1
does, so the scheduler half of the pin rests on case 1's scheduled
create and its re-arm assertion.
- **A6 stays green on both trees.** The delete pass re-checks the disk
under the per-key lock, which is a second guard. A8 removes both guards
and turns case 3 red on both trees.
- **A1 reds case 4 here but not at BASE,** because the old ENOENT case
passed without any sweep.
## Gates, lint and typecheck (at `43fef097df`)
- **Gates:** `dispatch-gates --commands --repo
objectstack-ai/objectstack` gives 49 commands, identical to the dispatch
list. All 49 ran. `--ran` with exit codes reads "49 derived, 49 run, 0
NOT-MEASURED, 0 UNRUN".
- `check:dual-build-cjs-loads` and `check:lean-entry-closure` first
exited 3 (PREREQUISITE NOT MET, no dist). Both were re-run green after
`turbo run build` (75 tasks, 73 from cache).
- `check:sourcemap-no-sources-content` was also re-run after the build:
70 packages, 554 maps.
- **Typecheck:** `pnpm --filter @objectstack/metadata-fs typecheck`
exits 0. `tsc --listFiles` on `tsconfig.test.json` names the test file
once.
- **Lint (narrowed to the one file):** `eslint --no-inline-config
--format json` reports 1 file, 0 errors and 0 warnings.
- `--print-config` returns a config for the file, so it is linted.
- Its parserOptions are `ecmaVersion` and `sourceType` only. Without
type-aware linting, the diff cannot change any other file's result.
- **Bytes:** `check:nul-bytes` exits 0, and a control-byte scan of the
file finds 0 lines.
## No changeset
This diff changes only a test. I built the package with `pnpm --filter
@objectstack/metadata-fs build` and searched its `files` (`dist`,
`README.md` and `CHANGELOG.md`). The test-only names `QUIET_SWEEPS`,
`reportedByFirstSweep`, `enoentServed` and `blindWatcher` have 0 hits.
The production controls `RESYNC_INTERVAL_MS` and `reportResyncFault` hit
2 and 4 files. `skip-changeset` is labelled.
## Acceptance notes
- This row's pin is the next refresh PR's list no longer naming this
file.
- Outside the module line: a single-file run of this package spends 12.5
to 15.2 s in vitest's import phase (the `import` figure in the summary
line), and no module line reports it. This is an observation only and is
not filed. Carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01P88ehrZ6hM19hBzdpsQTTo)_
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4f68ba1 commit 361e5f3
1 file changed
Lines changed: 83 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
42 | 71 | | |
43 | 72 | | |
44 | 73 | | |
| |||
58 | 87 | | |
59 | 88 | | |
60 | 89 | | |
61 | | - | |
62 | | - | |
| 90 | + | |
| 91 | + | |
63 | 92 | | |
64 | 93 | | |
65 | 94 | | |
| |||
75 | 104 | | |
76 | 105 | | |
77 | 106 | | |
| 107 | + | |
78 | 108 | | |
79 | 109 | | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
80 | 125 | | |
81 | 126 | | |
82 | 127 | | |
| |||
156 | 201 | | |
157 | 202 | | |
158 | 203 | | |
| 204 | + | |
159 | 205 | | |
160 | | - | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
161 | 210 | | |
162 | 211 | | |
163 | 212 | | |
| |||
171 | 220 | | |
172 | 221 | | |
173 | 222 | | |
174 | | - | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
175 | 232 | | |
| 233 | + | |
176 | 234 | | |
177 | 235 | | |
178 | 236 | | |
179 | 237 | | |
180 | 238 | | |
181 | 239 | | |
182 | | - | |
| 240 | + | |
183 | 241 | | |
| 242 | + | |
184 | 243 | | |
185 | 244 | | |
186 | 245 | | |
| |||
203 | 262 | | |
204 | 263 | | |
205 | 264 | | |
| 265 | + | |
| 266 | + | |
206 | 267 | | |
207 | 268 | | |
208 | | - | |
209 | | - | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
210 | 272 | | |
211 | 273 | | |
212 | 274 | | |
| |||
220 | 282 | | |
221 | 283 | | |
222 | 284 | | |
223 | | - | |
224 | 285 | | |
225 | 286 | | |
226 | 287 | | |
| |||
239 | 300 | | |
240 | 301 | | |
241 | 302 | | |
| 303 | + | |
242 | 304 | | |
243 | | - | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
244 | 308 | | |
245 | 309 | | |
246 | | - | |
| 310 | + | |
247 | 311 | | |
248 | 312 | | |
249 | 313 | | |
250 | 314 | | |
| 315 | + | |
251 | 316 | | |
| 317 | + | |
252 | 318 | | |
253 | 319 | | |
254 | 320 | | |
| |||
265 | 331 | | |
266 | 332 | | |
267 | 333 | | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
268 | 338 | | |
269 | 339 | | |
270 | 340 | | |
| 341 | + | |
271 | 342 | | |
272 | 343 | | |
273 | 344 | | |
| |||
276 | 347 | | |
277 | 348 | | |
278 | 349 | | |
279 | | - | |
| 350 | + | |
280 | 351 | | |
281 | 352 | | |
282 | 353 | | |
283 | 354 | | |
284 | 355 | | |
| 356 | + | |
285 | 357 | | |
286 | 358 | | |
287 | 359 | | |
| |||
0 commit comments