@cosyte/cli 0.0.4 → 0.0.6

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
@@ -17,6 +17,130 @@ still do. Each entry was assigned to the release whose tag first contains it, re
17
17
 
18
18
  ### Fixed
19
19
 
20
+ - **`pnpm phi-scan`'s all-mode walk was rooted at `test/__fixtures__` and `src` only, so 89 of this
21
+ repository's 123 tracked files were scanned by NEITHER of its two routes
22
+ (PHI-SCAN-WALK-ROOT-SCOPE).** The walk now roots at **`src`, `test` and `scripts`**, which opens 72
23
+ tracked files instead of 34.
24
+ - **Measured back to back on the base commit, and re-derived for this repository rather than ported
25
+ from a sibling.** A dashed SSN and an off-domain address written into `test/planted.test.ts`, in
26
+ this repository's own inline-message shape (a whole HL7 message as one `.ts` string literal with
27
+ `\r` escapes between its segments), exited **0** with `OK, no hits` in all mode, while naming the
28
+ same file in paths mode reported both at **exit 1** over the same bytes. A file written under
29
+ `scripts/` behaved identically. Both routes now report both.
30
+ - **All 38 newly opened files were hand-read.** Every message literal is a placeholder and the only
31
+ SSN/email shapes anywhere are the scanner's own declared synthetic payload, so the gap was one of
32
+ **enumeration**, not a live exposure: the defect was that the gate could not see those files, so
33
+ nothing would have caught a real value if one appeared.
34
+ - **`test` REPLACES `test/__fixtures__` rather than joining it.** Roots must stay disjoint: each is
35
+ walked independently and the results concatenated, so a nested root would enumerate every file
36
+ beneath it twice and report each hit twice. The fixture directory is still watched, through the
37
+ observation rule's other condition, **wherever git tracks files under it** (here, seven); only the
38
+ root a refusal is filed under changed.
39
+ - **One cover was LOST, and it is stated rather than implied away:** where git tracks NOTHING under
40
+ `test/__fixtures__`, an empty one no longer refuses. As a declared root it refused by the
41
+ opened-nothing floor whatever git carried; as an ordinary directory it contributes no entry and the
42
+ reconciliation has no expected path to miss. A test pins it.
43
+ - **`scripts/` is a root because the scanner, its allow-list and its override log live there**, so
44
+ the one directory guaranteed to hold PHI-shaped text was the one nothing enumerated. All nine
45
+ files there were measured against the detector before the root was declared: no hits.
46
+ - **The cost of that root nobody would guess: the allow-list's own bytes.** The allow-list documents
47
+ `ID <value>` as a synthetic id "matching an SSN / MRN / member-id shape", and the dashed-SSN check
48
+ consults no allow-list, so an `ID` entry written in that dashed shape now reds the gate on the
49
+ allow-list itself. Latent today (the shipped file declares its only id in the `MRN-` form, and a
50
+ test pins that). **The remedy is to spell the id in a shape the check does not match**, never to
51
+ make that check consult the allow-list (which would delete a detection) and never to exempt the
52
+ file (which would leave the likeliest place for a real value unswept).
53
+ - **A narrowing that came with it:** `test/__fixtures__` is no longer a declared root, so a live or
54
+ dangling symbolic link at that path is now an enumerated entry and is refused outright, whatever
55
+ it points at. Only the three top-level roots can still be followed.
56
+ - **`test/scripts/phi-scan.test.ts` is exempt from the sweep, and is the only exempt path.** It
57
+ carries violator literals on purpose, as the positive half of the scanner's own tests. The
58
+ exemption is applied **after the read**, so the file still counts as observed and an unreadable
59
+ one still refuses; it is **scoped to the sweep**, so naming the file explicitly still reports
60
+ every hit; and it is **per path, never a pattern**.
61
+ - **What this does NOT buy, stated because a wider reading would be false:** the detector is still
62
+ the cross-cutting SSN + email floor, over 38 more files. Structured, field-level detection remains
63
+ unimplemented, and a test now pins that limit rather than leaving it as prose.
64
+ - **`--staged` is deliberately unchanged**, because widening it changes what a commit is blocked on.
65
+ The two routes therefore differ widely, and the scanner's own documentation says by how much.
66
+ - **Four claims about which directories are deliberately NOT scan roots are now checks rather than
67
+ prose**, after two of them were measured false: `docs-content/` and `.changeset/` each carry one
68
+ tracked non-markdown file, and the repository root is not clean under the detector (the `author`
69
+ field carries a real off-domain contact address). `documentation/` and `.github/` were correct.
70
+
71
+ - **`pnpm phi-scan` printed `OK, no hits` and exited 0 over a corpus it never opened
72
+ (PHI-SCAN-OBSERVED-NOTHING-IS-GLOBAL).** A declared scan root that the walk never observed is now
73
+ a refusal at **exit 2**, in the all-mode sweep CI runs. Each root's walk is reconciled against
74
+ `git ls-files`, and two independent conditions refuse: the root contributed **nothing**, or git
75
+ tracks an in-scope file under the root that the walk did not open.
76
+ - **Six states measured on this repository, every one of them previously exiting 0 with
77
+ `OK, no hits`:** the root missing; the root emptied; the root a **dangling** symbolic link; the
78
+ root a **live** symbolic link to a directory outside the repository; a single tracked fixture
79
+ removed from the working tree with the rest of the root still opened; and `src` moved away.
80
+ - **The dangling case is why a kind check cannot stand in for this rule.** `existsSync` follows
81
+ the link and answers false, so `walk()` returns before `readdirSync` and the existing
82
+ not-a-regular-file refusal never fires. Nothing about the entry is ever inspected, so no check
83
+ on its kind can reach it. Refusing on what was **observed** needs no opinion about the entry.
84
+ - **A denominator is deliberately not what this is.** A count counts the roots and the files that
85
+ did exist, so a healthy-looking total is exactly what a starved root produces. This scanner
86
+ prints no file count and one was not added.
87
+ - **Existence is not observation, which is why both conditions ship.** Refusing only a missing
88
+ root leaves the emptied one open; refusing only an empty result leaves the swapped one open,
89
+ because a root pointed at another directory opens plenty. Neither subsumes the other.
90
+ - **Exit 2 was derived from this scanner's own contract, not ported from a sibling.** `1` means
91
+ "hits found" here; `walk()` already raises an unreadable root as an invocation failure, and a
92
+ root replaced by a regular file already exits 2 through `readdirSync`. Sibling scanners disagree
93
+ on this code, and carrying one across would have been the defect.
94
+ - **`git ls-files` failing refuses rather than answering the empty set**, because an empty answer
95
+ is indistinguishable from "this root tracks nothing" and would switch the rule off in silence.
96
+ - **The rule is one-directional on purpose.** A tracked in-scope file the walk missed refuses; an
97
+ untracked working-tree file the walk found does not, because scanning more than git carries is
98
+ the safe direction.
99
+ - **Scope, stated rather than left to be inferred:** all-mode only. `--staged` is a diff and not a
100
+ corpus, and widening it would change what a **commit** is blocked on, which is a separate
101
+ decision. Naming paths explicitly is unchanged.
102
+ - **Narrowed, not closed, and still disclosed in the module header:** a scan root that is itself a
103
+ live link is still followed. It is now refused whenever git tracks an in-scope file under the
104
+ root that the link's target does not also carry **at the same relative path**, so a link to an
105
+ unrelated directory refuses; the reconciliation compares path **sets** rather than the bytes git
106
+ carries at those paths, so a target mirroring the tracked names still passes at exit 0, and a
107
+ root git tracks nothing under is the degenerate case of that rather than the whole of it. An
108
+ **ancestor** of a scan root remains out of the staged route's scope, and paths mode still follows
109
+ a link a caller names.
110
+ - **A present-but-unreadable `phi-scan-overrides.md` exited 1, the code reserved for "hits found".**
111
+ `loadOverrideLog` threw a raw filesystem error past every handler while its sibling reader,
112
+ `loadAllowList`, had already been wrapped. It now exits 2 with a diagnostic. A caller branching on
113
+ the exit code read a broken invocation as a PHI finding.
114
+ - **A red pre-publish gate showed a red X and merged anyway, because `ci / prepublish` was a
115
+ required check nowhere (CI-REQUIRED-CHECKS).** The shared pipeline this repo calls grew a
116
+ `prepublish` job on 2026-08-05 (`cosyte/.github#35`, `6142ac4`; its second layer defaulted on in
117
+ `#36`, `90936ea`), so `ci.yml` began emitting a `ci / prepublish` context on every pull request
118
+ here **with no commit landing in this repo**. Repository ruleset `19907924` did not name it, so
119
+ the job could fail and the merge still landed on `main`, which is the branch that publishes.
120
+ `ci / prepublish` is now a required context, `integration_id`-pinned like the other six.
121
+ - **What it gates is this package's own worst shipped defect.** The job is an offline manifest
122
+ lint that refuses a dependency specifier no registry can resolve, plus a probe that packs this
123
+ tree and installs the tarball into a clean directory. `@cosyte/cli@0.0.1` and `0.0.2` reached
124
+ the registry carrying `file:vendor/*.tgz` specifiers and are permanently uninstallable; the
125
+ manifest lint would have refused both. A gate that catches that and then cannot block the merge
126
+ reintroducing it is documentation.
127
+ - **The order was load-bearing and is recorded because it is easy to get backwards.** The context
128
+ name was read off a real `pull_request` check run before the ruleset was written, never off the
129
+ workflow's `name:` field. Requiring a context nothing emits does not fail a pull request, it
130
+ leaves it pending and unmergeable forever. A census of the eight most recent head shas here
131
+ (`#27` through `#34`) finds `ci / prepublish` **zero** times, because the newest of them merged
132
+ before the upstream job existed, so it could not have been required any earlier.
133
+ - **`ci.yml`'s banner now covers the hazard that actually bit.** Every previous wording of it was
134
+ scoped to splitting a step out of `verify` locally. The `uses:` reference is unpinned, so a job
135
+ added upstream emits a new `ci / <job>` context here with no commit in this repo, and it always
136
+ arrives unrequired.
137
+ - **Deliberately NOT in this change: `release.yml`'s version-PR trap note.** It carries a stale
138
+ required-context count and a claim about the "Version Packages" PR arriving with zero check runs
139
+ whose truth depends on whether `RELEASE_PR_TOKEN` is authoring that PR. Two attempts to correct
140
+ it inside this change each produced a fresh false claim: the first a false operational premise,
141
+ the second a false claim about the note's own history. So it is cut out to its own change rather
142
+ than rewritten a third time. Nothing about it is made worse here; it is left exactly as it was.
143
+
20
144
  - **The shipped documentation sidebar was off the canonical IA spine, and it was holding up the
21
145
  docs site's deploy (CLI-SIDEBAR-IA-NONCANONICAL).** `docs-content/sidebars.json` declared two
22
146
  top-level categories that are not on the spine, **"MCP server"** and **"Reference"**. The docs
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://cosyte.com/tile/cosyte-lockup-tile-on-dark-1200x300.png">
3
- <img alt="Cosyte: a plus mark set in two overlapping rounded squares, one solid and one outlined, beside the Cosyte wordmark" src="https://cosyte.com/tile/cosyte-lockup-tile-on-light-1200x300.png">
4
- </picture>
1
+ <a href="https://cosyte.com">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cosyte.com/tile/cosyte-lockup-tile-on-dark-1200x300.png">
4
+ <img alt="Cosyte: a plus mark set in two overlapping rounded squares, one solid and one outlined, beside the Cosyte wordmark" src="https://cosyte.com/tile/cosyte-lockup-tile-on-light-1200x300.png">
5
+ </picture>
6
+ </a>
5
7
 
6
8
  # @cosyte/cli
7
9
 
@@ -7,7 +7,7 @@ var types_js = require('@modelcontextprotocol/sdk/types.js');
7
7
  var util = require('util');
8
8
 
9
9
  // src/core/version.ts
10
- var VERSION = "0.0.4";
10
+ var VERSION = "0.0.6";
11
11
 
12
12
  // src/core/exit-codes.ts
13
13
  var EXIT = {