@0xcraft/powershot 1.1.1 → 1.1.3

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/dist/session.js CHANGED
@@ -105,7 +105,13 @@ export class Session {
105
105
  verified: findings.filter((f) => f.class === 'verified').length,
106
106
  judged: findings.filter((f) => f.class === 'judged').length,
107
107
  state: verdict.state,
108
- notLookedAt: verdict.notLookedAt,
108
+ notLookedAt: [...verdict.notLookedAt],
109
+ coverage: verdict.coverage,
110
+ verifyOnly: verdict.verifyOnly,
111
+ minSeverity: verdict.minSeverity,
112
+ filesReviewed: verdict.filesReviewed,
113
+ deterministicChecks: verdict.deterministicChecks,
114
+ scopeDetails: verdict.scopeDetails ? [...verdict.scopeDetails] : undefined,
109
115
  };
110
116
  this.save();
111
117
  }
@@ -47,13 +47,19 @@ function pythonFindings(g) {
47
47
  const python = g.foreign.filter((f) => f.pack.name === 'python');
48
48
  if (python.length === 0)
49
49
  return [];
50
- const local = localModules(g.root);
51
50
  const findings = [];
51
+ const modules = new Map();
52
52
  for (const file of python) {
53
53
  // the manifests governing this file, not just the repository's own
54
- const manifest = pythonManifest(g.root, dirname(join(g.root, file.path)));
54
+ const fileDir = dirname(join(g.root, file.path));
55
+ const manifest = pythonManifest(g.root, fileDir);
55
56
  if (!manifest)
56
57
  continue;
58
+ let local = modules.get(fileDir);
59
+ if (!local) {
60
+ local = localModules(g.root, fileDir);
61
+ modules.set(fileDir, local);
62
+ }
57
63
  for (const imported of file.pack.imports?.(file.tree.rootNode) ?? []) {
58
64
  const line = imported.node.startPosition.row + 1;
59
65
  if (!file.changed.added.has(line))
@@ -64,8 +64,9 @@ engine. The engine does not depend on a workflow provider or terminal layout.
64
64
  | `src/manifest.ts` | Completion state and the authoritative run record | Rendering |
65
65
  | `src/verifiers/` | Deterministic check implementations | Model calls |
66
66
  | `src/judges/` | Prompt data, bounded model loop, tool adapter | Git target selection |
67
- | `src/lang/` | Language-pack data and optional language oracles | Cross-run policy |
67
+ | `src/lang/` | Language-pack data, isolated parser workers, optional language oracles | Cross-run policy |
68
68
  | `src/report/` | Pure output adapters | Re-running or reinterpreting a review |
69
+ | `src/github/` | GitHub REST transport and pull-request publication reconciliation | Review decisions or report rendering |
69
70
  | `src/bench.ts` | Historical and labelled evaluation | Production command dispatch |
70
71
  | `src/session.ts`, `src/cache.ts` | Reuse of completed judge work | Completion decisions |
71
72
 
@@ -107,7 +108,7 @@ sequenceDiagram
107
108
  Plan->>Judge: bounded related-file bundles
108
109
  Judge-->>Manifest: judged findings + usage
109
110
  end
110
- Manifest->>Manifest: compute complete / partial / failed
111
+ Manifest->>Manifest: compute full or portable completion / partial / failed
111
112
  Manifest->>Report: one result, many formats
112
113
  Report-->>User: terminal, Markdown, SARIF, JSON
113
114
  ```
@@ -126,6 +127,12 @@ A run can contain a typed TypeScript file beside a Python file or a TypeScript f
126
127
  excluded from `tsconfig`. Capabilities therefore live on each selected file. A checker
127
128
  available somewhere in the run is not evidence that it inspected every file.
128
129
 
130
+ The policy decides what an absent capability means. Under default `portable` coverage,
131
+ self-contained syntax and manifest oracles remain a complete verdict while unavailable
132
+ `types`, `references`, and `python-types` are recorded as optional depth. Under
133
+ `strict` coverage, or when a check is named explicitly, the same gap is required and
134
+ makes the review partial.
135
+
129
136
  ### Monorepo grounding follows the change
130
137
 
131
138
  For each changed TypeScript or JavaScript file, grounding inspects only its ancestor
@@ -140,21 +147,40 @@ exists, only changed files are parsed and type-dependent capabilities remain abs
140
147
  That keeps a configless or mixed-language monorepo proportional to the review rather
141
148
  than to the repository.
142
149
 
150
+ Python dependency grounding follows the same rule. Local modules are discovered from
151
+ direct entries on each changed file's ancestor chain and conventional `src`, `lib`, or
152
+ `python` roots. It never recursively crawls an unrelated monorepo tree.
153
+
154
+ ### Grammar memory is isolated by language
155
+
156
+ Tree-sitter WASM compilation outlives its JavaScript parser objects. Keeping every
157
+ declared grammar in one process pushed measured RSS past 690MB. Production parsing
158
+ therefore groups changed files by language, sends at most 128 files or 8MB of source to
159
+ one disposable worker, hydrates plain AST data in the parent, and terminates the worker.
160
+ Compiled-grammar memory is bounded by one language batch rather than by the
161
+ repository's language count; hydrated AST data remains proportional to the selected
162
+ diff, not the whole repository. A parser failure for a declared language fails
163
+ selection instead of quietly waiving the file.
164
+
143
165
  ### The manifest owns completion
144
166
 
145
167
  Findings alone cannot distinguish a clean review from an interrupted or unsupported
146
- one. `RunManifest` accounts for selected files, executed checks, judge units, failures,
147
- limits, and skips. Renderers and the CLI consume that state instead of deriving their
148
- own verdict.
168
+ one. `RunManifest` accounts for selected files, executed and unavailable checks, judge
169
+ units, failures, limits, and skips. `state` answers whether required work completed;
170
+ `coverage` separately says `full` or `portable`. Renderers and the CLI consume that
171
+ record instead of deriving their own verdict.
149
172
 
150
173
  ```mermaid
151
174
  stateDiagram-v2
152
175
  [*] --> Selected
153
- Selected --> Complete: every file and unit accounted for
154
- Selected --> Partial: capability, budget, or cancellation gap
176
+ Selected --> Full: every file, unit, and enriched oracle accounted for
177
+ Selected --> Portable: required work complete; enriched gaps named
178
+ Selected --> Partial: required oracle, budget, or cancellation gap
155
179
  Selected --> Failed: required stage or file failed
156
- Complete --> Exit0: no findings
157
- Complete --> Exit1: findings
180
+ Full --> Exit0: no findings
181
+ Full --> Exit1: findings
182
+ Portable --> Exit0: no findings
183
+ Portable --> Exit1: findings
158
184
  Partial --> Exit3
159
185
  Failed --> Exit3
160
186
  ```
@@ -178,8 +204,9 @@ and duplicated runs waste both time and tokens.
178
204
  ### Add a language pack
179
205
 
180
206
  Add grammar data and conventions in `src/lang/packs.ts`, then add a dedicated fixture
181
- to `src/langtest.ts`. Language packs run in separate processes so all grammars remain
182
- covered without sharing one unbounded WASM heap.
207
+ to `src/langtest.ts` and include it in the all-languages review regression. Development
208
+ fixtures and production parsing both isolate grammars by process, so no supported pack
209
+ shares one unbounded WASM heap with the rest.
183
210
 
184
211
  ### Add a report format
185
212
 
package/docs/ci.md CHANGED
@@ -16,6 +16,11 @@ There are two independent decisions:
16
16
  2. Do findings block the change? Set this per repository. Exit `1` is a complete
17
17
  verdict with findings, not an engine failure.
18
18
 
19
+ A completed verdict has a separate coverage level. `full` means every applicable
20
+ configured oracle ran. `portable` means every self-contained oracle ran while missing
21
+ compiler/reference depth was named. Set `"coverage": "strict"` in
22
+ `powershot.config.json` when portable depth must become exit `3` instead.
23
+
19
24
  | Exit | Meaning | Recommended CI handling |
20
25
  |---:|---|---|
21
26
  | `0` | Complete, no findings | Pass |
@@ -36,6 +41,10 @@ name: PowerShot
36
41
  on:
37
42
  pull_request:
38
43
 
44
+ concurrency:
45
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
46
+ cancel-in-progress: true
47
+
39
48
  permissions:
40
49
  contents: read
41
50
  pull-requests: write
@@ -49,8 +58,6 @@ jobs:
49
58
  with:
50
59
  fetch-depth: 0
51
60
 
52
- - run: npm ci --ignore-scripts
53
-
54
61
  - uses: xcrft/powershot@v1
55
62
  with:
56
63
  verify-only: 'true'
@@ -60,16 +67,41 @@ jobs:
60
67
  fail-on-findings: 'true'
61
68
  ```
62
69
 
63
- Type-aware checks use the checked-out project's declarations, so install its
64
- dependencies before PowerShot. Lifecycle scripts are disabled here because pull
65
- request code is untrusted; use the equivalent safe install for another package
66
- manager. For a monorepo without a root install, repeat the safe install step with the
67
- relevant package `working-directory`. PowerShot finds nested `tsconfig.json` and
68
- `tsconfig.*.json` files automatically; the workflow does not need to list projects.
70
+ Portable coverage deliberately needs no repository install. This keeps fork and
71
+ private-monorepo pull requests free of registry credentials while still running each
72
+ declared language's syntax-backed oracles. When a trusted job already has dependencies,
73
+ PowerShot uses the available declarations and can reach `full` coverage. Do not pass a
74
+ private package token into a pull-request job merely to enrich review depth.
75
+
76
+ PowerShot finds nested `tsconfig.json` and `tsconfig.*.json` files along changed-file
77
+ ancestor chains; the workflow does not list projects. Python local-module discovery is
78
+ bounded the same way. Foreign-language grammars run in disposable per-language workers
79
+ and bounded batches, so all declared languages can coexist in one monorepo review.
69
80
 
70
81
  Set `upload-sarif: 'false'` and omit `security-events: write` when GitHub code scanning
71
82
  is unavailable or the workflow should not publish SARIF.
72
83
 
84
+ `comment: 'true'` maintains one summary through a hidden marker scoped to the caller's
85
+ workflow file and job. Reruns update only that exact `github-actions[bot]` comment, so
86
+ another workflow or job using the same bot identity is left alone. Each candidate also
87
+ records its pull-request head. A new head gets a new candidate, which means an old run
88
+ never patches or retires the current head's comment. The first scoped run replaces the
89
+ newest unmarked legacy `## PowerShot` summary from v1.1.2 or older without claiming the
90
+ ambiguous legacy comment through `PATCH`.
91
+
92
+ The comment leads with the verdict, effective severity threshold, review mode, and
93
+ aggregate file/check counts. Portable gaps and files outside parser coverage stay
94
+ visible under a collapsed coverage section without filling the timeline with paths.
95
+ The generated `powershot.manifest.json` keeps the per-file accounting for workflows
96
+ that want to persist it as an artifact.
97
+
98
+ PowerShot checks the target head throughout reconciliation and removes its own
99
+ just-created candidate if it observes a changed head. Simultaneous same-head runs
100
+ relist and converge on one scoped candidate when they complete. Keep the example's
101
+ `concurrency` block to reduce overlap and canceled stale work. GitHub's issue-comment
102
+ REST API has no atomic create-if-absent operation, and cancellation cannot stop a REST
103
+ request already in flight, so concurrency reduces but cannot eliminate that window.
104
+
73
105
  `inline-comments: 'true'` requires `pull-requests: write`. It publishes at most ten
74
106
  findings as one review. Only deterministic `verified` findings with `proven`
75
107
  confidence, severity `medium` or higher, and a GitHub-confirmed added line qualify.
@@ -94,10 +126,10 @@ lives at [`examples/github-actions/action.yml`](../examples/github-actions/actio
94
126
  | `comment` | `true` | Maintain a pull-request comment |
95
127
  | `inline-comments` | `false` | Post up to ten proven verified findings as one inline review |
96
128
  | `fail-on-findings` | `false` | Turn a complete finding verdict into a failed job |
97
- | `approve` | `false` | Approve only a complete, clean review |
129
+ | `approve` | `false` | Approve only a complete, clean, full-coverage review |
98
130
 
99
- The outputs are `findings` and `complete`. `complete` is the important one when a
100
- later job decides whether to publish or deploy.
131
+ The outputs are `findings`, `complete`, and `coverage`. Gate infrastructure on
132
+ `complete`; use `coverage == 'full'` for decisions that require semantic depth.
101
133
 
102
134
  ## Direct CLI on GitHub Actions
103
135
 
@@ -108,7 +140,7 @@ step inside a larger quality job. The complete example is
108
140
  The core pattern is:
109
141
 
110
142
  ```bash
111
- npm install --global --ignore-scripts @0xcraft/powershot@1.1.1
143
+ npm install --global --ignore-scripts @0xcraft/powershot@1.1.2
112
144
 
113
145
  STATUS=0
114
146
  psh review --verify-only \
@@ -156,6 +188,7 @@ and artifact declaration.
156
188
  - Run `--verify-only` as the fast required check; add model judges only where their
157
189
  cost and latency are intentional.
158
190
  - Treat exit `2`, `3`, and `130` as infrastructure or completeness failures.
191
+ - Read the manifest or Action `coverage` output before treating portable depth as full.
159
192
  - Generate every report from one invocation.
160
193
  - Publish the Markdown report for humans and SARIF or Code Quality for annotations.
161
194
  - Pin the PowerShot source version in protected workflows.
@@ -3,6 +3,10 @@ name: PowerShot
3
3
  on:
4
4
  pull_request:
5
5
 
6
+ concurrency:
7
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
8
+ cancel-in-progress: true
9
+
6
10
  permissions:
7
11
  contents: read
8
12
  pull-requests: write
@@ -16,11 +20,6 @@ jobs:
16
20
  with:
17
21
  fetch-depth: 0
18
22
 
19
- # Type-aware checks need the repository's declared types. Keep lifecycle
20
- # scripts disabled when pull-request code is not trusted. In a monorepo,
21
- # install at the workspace root or set working-directory to the package root.
22
- - run: npm ci --ignore-scripts
23
-
24
23
  - uses: xcrft/powershot@v1
25
24
  with:
26
25
  verify-only: 'true'
@@ -19,7 +19,7 @@ jobs:
19
19
  node-version: '24'
20
20
 
21
21
  - name: Install PowerShot
22
- run: npm install --global --ignore-scripts @0xcraft/powershot@1.1.1
22
+ run: npm install --global --ignore-scripts @0xcraft/powershot@1.1.2
23
23
 
24
24
  - name: Review pull request
25
25
  env:
@@ -5,7 +5,7 @@ powershot:
5
5
  variables:
6
6
  GIT_DEPTH: "0"
7
7
  before_script:
8
- - npm install --global --ignore-scripts @0xcraft/powershot@1.1.1
8
+ - npm install --global --ignore-scripts @0xcraft/powershot@1.1.2
9
9
  script:
10
10
  - |
11
11
  STATUS=0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xcraft/powershot",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Oracle-first code review for machine-written code, with deterministic verification and CI-ready reports.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "aglumova <alina.glumova@gmail.com>",