@cosyte/script-utils 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -12,6 +12,20 @@ pre-alpha rule. See
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [0.1.1] - Unreleased
16
+
17
+ ### Fixed
18
+
19
+ - **`phi-scan`: the per-root observation rule is answered from the WALK's reads only.** It was
20
+ answered from every read the run took, including the index-union reads of the bytes git carries,
21
+ so a scan root that was missing or empty on disk was credited whenever git tracked a file under
22
+ it. In a real repository every root holds tracked files, so the rule never fired for the state it
23
+ exists to catch. Measured before the change: two repositories with `src` emptied on disk, differing
24
+ only in whether `src/index.ts` was tracked, exited at the refuse code and at the clean code with
25
+ `OK: no hits`. **Such a root now refuses at the `refuse` code, naming it.** Those tracked files are
26
+ still read from the bytes git carries and a hit in them is printed before the refusal; the
27
+ completeness rule still counts every read, and a root the walk reads is not refused.
28
+
15
29
  ## [0.1.0] - Unreleased
16
30
 
17
31
  ### Changed
package/README.md CHANGED
@@ -314,7 +314,7 @@ paths, and the `all`-mode sweep); reading the allow-list and the override log; t
314
314
  the union of the working-tree walk with the bytes git carries at every index path, deduplicated **by
315
315
  content** under git's own `blob <len>\0` framing; the completeness rule (a target the run enumerated
316
316
  and never read refuses, naming the paths); the per-root observation rule (`all` mode refuses unless
317
- every `scanRoots` entry yielded a file that was read, naming the starved roots); every refusal; and a
317
+ every `scanRoots` entry yielded a file the WALK read, naming the starved roots); every refusal; and a
318
318
  cross-cutting detection floor that finds a dashed SSN shape and an email at an undeclared domain over
319
319
  every file, always.
320
320
 
@@ -359,12 +359,13 @@ because without it the sweep is the working-tree walk's word alone. A freshly sc
359
359
  `git init` and commit before an `all`-mode run means anything.
360
360
 
361
361
  **Every scan root has to produce something.** `all` mode refuses when a `scanRoots` entry yielded no
362
- file that was read, and names it. A root that is missing, unreadable, or whose every file your read
363
- filter drops used to leave the sweep quietly narrower than its own configuration said, and one
364
- productive root made the whole run look productive. If you narrow `scanRoots`, this is the tier that
365
- tells you what the narrowing stopped reading. A root naming a regular file is scanned as one target;
366
- one naming a symbolic link is refused rather than followed; one naming a directory that cannot be
367
- listed is refused, naming the path.
362
+ file the walk read, and names it, even when git tracks files under it: those are still read from the
363
+ index, but what git carries cannot vouch for a directory on disk. A root that is missing, unreadable,
364
+ or whose every file your read filter drops used to leave the sweep quietly narrower than its own
365
+ configuration said, and one productive root made the whole run look productive. If you narrow
366
+ `scanRoots`, this is the tier that tells you what the narrowing stopped reading. A root naming a
367
+ regular file is scanned as one target; one naming a symbolic link is refused rather than followed;
368
+ one naming a directory that cannot be listed is refused, naming the path.
368
369
 
369
370
  **`scanRoots` bounds the WALK, not the index.** `all` mode reads the bytes git carries at every
370
371
  tracked path, whatever your roots say, because a root list answers what is on disk under it and the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosyte/script-utils",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Zero-dependency helpers for the repo-local gate scripts in @cosyte/* repos.",
5
5
  "keywords": [
6
6
  "cli",
package/phi-scan.d.ts CHANGED
@@ -159,13 +159,18 @@ export interface PhiScanConfig {
159
159
  * this contract reserves for HITS FOUND. A MISSING root is skipped by the WALK, which is unchanged
160
160
  * from the copied scanners, and is then caught by the rule below.
161
161
  *
162
- * 🛑 EVERY ROOT MUST YIELD AT LEAST ONE FILE THAT WAS ACTUALLY READ, OR `all` MODE REFUSES AND
163
- * NAMES THE STARVED ROOTS. That is what closes the class the paragraph above used to end with:
164
- * a root that contributes nothing WITHOUT SAYING SO. All three of the known members are in it - a
165
- * missing root, an UNREADABLE root (reported the same way a missing one is), and a root whose
166
- * every file the read filter drops, which is what a `.md` file root does under the default
162
+ * 🛑 EVERY ROOT MUST YIELD AT LEAST ONE FILE THE WALK READ, OR `all` MODE REFUSES AND NAMES THE
163
+ * STARVED ROOTS. That is what closes the class the paragraph above used to end with: a root that
164
+ * contributes nothing WITHOUT SAYING SO. All three of the known members are in it - a missing
165
+ * root, an UNREADABLE root (reported the same way a missing one is), and a root whose every file
166
+ * the read filter drops, which is what a `.md` file root does under the default
167
167
  * `isWalkReadable`. A root is a scope decision, and a scope decision that silently selected
168
168
  * nothing is the sweep reporting on a corpus it never had.
169
+ *
170
+ * THE INDEX HALF NEVER CREDITS A ROOT. A root that is missing or empty on disk is starved even
171
+ * when git tracks files under it: those files are still read from the bytes git carries, and any
172
+ * hit in them is reported before the refusal, but what git carries cannot vouch for a directory
173
+ * on disk.
169
174
  */
170
175
  scanRoots: readonly string[];
171
176
 
package/phi-scan.js CHANGED
@@ -1287,14 +1287,16 @@ class PhiScan {
1287
1287
  }
1288
1288
 
1289
1289
  /**
1290
- * Did this root yield at least one file whose bytes were ACTUALLY READ?
1290
+ * Did this root yield at least one file the WALK actually read?
1291
1291
  *
1292
- * IT IS ASKED OF `read`, WHICH IS EVIDENCE OF OBSERVATION RATHER THAN A PLAN TO OBSERVE, and it
1293
- * is asked per root rather than of the union, because the union is exactly what hides a starved
1294
- * root: one productive root makes the whole sweep look productive.
1292
+ * IT IS ASKED OF THE WALK'S READS, WHICH ARE EVIDENCE OF OBSERVATION RATHER THAN A PLAN TO
1293
+ * OBSERVE, and never of the index union's: the union reads the bytes git carries at a tracked
1294
+ * path, and that cannot vouch for a directory on disk. It is asked per root rather than of the
1295
+ * whole sweep, because the whole sweep is exactly what hides a starved root: one productive root
1296
+ * makes the whole sweep look productive.
1295
1297
  *
1296
1298
  * @param {string} root A normalised scan root.
1297
- * @param {Set<string>} read The repo-relative paths this run opened.
1299
+ * @param {Set<string>} read The repo-relative paths the walk opened.
1298
1300
  * @returns {boolean}
1299
1301
  */
1300
1302
  anyReadUnder(root, read) {
@@ -1751,6 +1753,11 @@ class PhiScan {
1751
1753
 
1752
1754
  const walkFailure = sweep(targets);
1753
1755
  if (walkFailure !== null) return walkFailure;
1756
+ // WHAT THE WALK READ, FROZEN BEFORE THE UNION ADDS TO `read`. The per-root observation rule is
1757
+ // answered from this and nothing else: the union reads what git carries at a tracked path, which
1758
+ // is not evidence that anything under a root exists on disk. `read` itself keeps both halves,
1759
+ // because the completeness rule needs every read the run took.
1760
+ const walkRead = new Set(read);
1754
1761
 
1755
1762
  // THE INDEX ROUTE'S OWN REFUSALS, RAISED HERE RATHER THAN WHERE THEY ARE COMPUTED (AC-15). An
1756
1763
  // unmerged entry or a tracked link anywhere in the index refuses the whole sweep, and the walk
@@ -1799,9 +1806,10 @@ class PhiScan {
1799
1806
  // target was read; it cannot ask whether a root produced a target in the first place, and a
1800
1807
  // root that produces none is the silently-narrowed sweep: a typo, a directory that moved, a
1801
1808
  // root whose every file the read filter drops. One productive root makes the whole run look
1802
- // productive, so the question is asked per root and answered from `read`.
1809
+ // productive, so the question is asked per root and answered from `walkRead`: a root git
1810
+ // tracks files under and that holds nothing on disk is starved, whatever the union read there.
1803
1811
  const starved =
1804
- index === null ? [] : this.cfg.scanRoots.filter((root) => !this.anyReadUnder(root, read));
1812
+ index === null ? [] : this.cfg.scanRoots.filter((root) => !this.anyReadUnder(root, walkRead));
1805
1813
 
1806
1814
  // Hits FIRST, so nothing below can swallow one.
1807
1815
  this.reportHits(hits);