vouchington-tooling 0.40.0 → 0.41.0

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/README.md CHANGED
@@ -429,18 +429,20 @@ architectures to every `os`, `cpu`, and `libc` selector represented in the lockf
429
429
  `engines` constraint from the audit copy of the lockfile, and validates the JSON report. Dropping
430
430
  `engines` keeps `pnpm fetch` from skipping optional packages that exclude the running Node.js;
431
431
  pnpm 12's `fetch` ignores `force`, so their licenses would otherwise report as Unknown.
432
- Packages are fetched into a dedicated owner-only store under the pnpm cache
433
- (`dependency-license-audit-store`) so a later audit reuses content-addressed packages instead of
434
- downloading every platform again, without writing those packages into the developer store.
432
+ Packages are fetched into a private store inside that temporary workspace. Each audit has its own
433
+ store, and workspace cleanup removes every downloaded package when the audit succeeds or fails,
434
+ without changing the developer's pnpm store. The exported options no longer accept a `storeDir`
435
+ override because caller-owned paths cannot be safely removed; callers that provide a custom
436
+ `prepareWorkspace` own the returned workspace and its nested store lifecycle.
435
437
  Pass explicit denied SPDX IDs and prefixes, exact aliases, and justified allowlist scopes to
436
438
  `evaluatePnpmLicenseReport`. Unknown, malformed, and custom SPDX references fail closed. Allowlist
437
439
  scopes are either intentionally global or an exact package-name set; the library returns structured
438
440
  violations and does not format CI-provider diagnostics.
439
441
  When present, the repository `.npmrc` is copied into the owner-private temporary workspace so pnpm
440
- can authenticate to the same registries. The workspace is removed when the audit finishes, when the
441
- process receives SIGINT, SIGTERM, or SIGHUP, and on the next audit if the previous process died
442
- first, including SIGKILL. Each workspace records its owner's PID so a later audit can delete
443
- directories whose owner is gone.
442
+ can authenticate to the same registries. The workspace and its package store are removed when the
443
+ audit finishes, when the process receives SIGINT, SIGTERM, or SIGHUP, and on the next audit if the
444
+ previous process died first, including SIGKILL. Each workspace records its owner's PID so a later
445
+ audit can delete directories whose owner is gone.
444
446
 
445
447
  `session-friction` is an opt-in capture and reporting library. Callers supply the session id,
446
448
  absolute log directory, host-independent observation, and journal loader; it does not inspect host
@@ -1,4 +1,4 @@
1
- export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n require-up-to-date Require HEAD to include a fetched remote branch\n gitleaks-directory-scan Scan a directory with Gitleaks\n ast-grep-examples Run AST-grep rule examples\n ast-grep-pack Print shipped unconditional AST-grep pack paths as JSON\n gha-workspace-policy Check GitHub Actions workspace safety policy\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n download-optional-run-artifacts Download optional artifacts from the current run\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n vitest-report-attempt Write or read a Vitest report-attempt marker\n prepare-vitest-reports Validate and select Vitest report JSON files\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n harness-admission-lane Compute a GITHUB_RUN_ID admission lane for fleet fan-out\n harness-assert-gates Fail if any named HARNESS_*_ENABLED gate is enabled\n gha-collaborator-trust Classify authors as write-access collaborators or not\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n link-skill Link one packaged skill into an explicit consumer directory\n retrospective-facts Gather immutable facts for a retrospective\n agent-blackboard Probe and journal an Agent Blackboard deployment\n mcp Serve the agent-blackboard journal tools over stdio (MCP)\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n [--median-threshold-floor <seconds>] Off unless set. Must be below the ceiling\n [--median-threshold-ceiling <seconds>] Default 360. Flags a five-sample median above this\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\nrequire-up-to-date --remote <name> --branch <name>\ngitleaks-directory-scan --config <path> [--directory <path>]\nast-grep-examples --rules <directory> --config <path>\nast-grep-pack\ngha-workspace-policy [--root <directory>] [--workflow-directory <directory>] [--action-directory <directory>]\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\ndownload-optional-run-artifacts (--name <name>... | --pattern <pattern>) --dir <directory>\nhost-pressure-diagnostics\nallocate-browser-safe-ports <count> [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\nvitest-report-attempt <write DIRECTORY SUITE|read ROOT>\nprepare-vitest-reports [primary-directory] [fallback-directory] [output-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--expected-sha256 SHA256] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nharness-admission-lane <lanes>\nharness-assert-gates <gate>...\ngha-collaborator-trust <owner/repo> [--allow-bot <login>]... < authors.json\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\nlink-skill <name> --source-root <skills-dir> --target-root <consumer-skills-dir> Link a packaged or repository-local skill\nretrospective-facts (--pr NUMBER | --branch NAME | --no-pr) [--repo OWNER/NAME] [--raw]\nagent-blackboard probe\nagent-blackboard journal append --mode interactive|autonomous --source-event-id ID --work-outcome OUTCOME --coverage-status STATUS --session-id UUID --agent NAME --version VERSION --file PATH --repository OWNER/NAME [--repository OWNER/NAME ...] [--parent-session-id UUID] [--timestamp ISO8601] [--coverage-source SOURCE,...] [--dropped-count N] [--outbox-directory PATH]\nagent-blackboard journal entries --session-id UUID\nagent-blackboard journal status --session-id UUID --outbox-directory PATH\nagent-blackboard journal flush --outbox-directory PATH [--session-id UUID]\nInteractive journal append requires --outbox-directory PATH.\nagent-blackboard snapshot partition --snapshot PATH --checksum SHA256 --counts '{\"sessions\":N,\"entries\":N,\"records\":N,\"bytes\":N}'\nagent-blackboard snapshot cleanup [--snapshot PATH] [--partition-directory PATH --receipt JSON]\nmcp\n (no args) Serve journal_append, journal_entries, outbox_status, outbox_flush,\n session_ensure, snapshot_export, and session_archive over stdio.\n Needs the optional @modelcontextprotocol/sdk peer (and zod).\n Launch it from inside the repository's git worktree.\n";
1
+ export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n require-up-to-date Require HEAD to include a fetched remote branch\n gitleaks-directory-scan Scan a directory with Gitleaks\n ast-grep-examples Run AST-grep rule examples\n ast-grep-pack Print shipped unconditional AST-grep pack paths as JSON\n gha-workspace-policy Check GitHub Actions workspace safety policy\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n download-optional-run-artifacts Download optional artifacts from the current run\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n vitest-report-attempt Write or read a Vitest report-attempt marker\n prepare-vitest-reports Validate and select Vitest report JSON files\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n harness-admission-lane Compute a GITHUB_RUN_ID admission lane for fleet fan-out\n harness-assert-gates Fail if any named HARNESS_*_ENABLED gate is enabled\n gha-collaborator-trust Classify authors as write-access collaborators or not\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n link-skill Link one packaged skill into an explicit consumer directory\n retrospective-facts Gather immutable facts for a retrospective\n agent-blackboard Probe and journal an Agent Blackboard deployment\n mcp Serve the agent-blackboard journal tools over stdio (MCP)\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n [--median-threshold-floor <seconds>] Off unless set. Must be below the ceiling\n [--median-threshold-ceiling <seconds>] Default 360. Flags a five-sample median above this\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\nrequire-up-to-date --remote <name> --branch <name>\ngitleaks-directory-scan --config <path> [--directory <path>]\nast-grep-examples --rules <directory> --config <path>\nast-grep-pack\ngha-workspace-policy [--root <directory>] [--workflow-directory <directory>] [--action-directory <directory>]\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\ndownload-optional-run-artifacts (--name <name>... | --pattern <pattern>) --dir <directory>\nhost-pressure-diagnostics\nallocate-browser-safe-ports <count> [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\nvitest-report-attempt <write DIRECTORY SUITE|read ROOT>\nprepare-vitest-reports [primary-directory] [fallback-directory] [output-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--expected-sha256 SHA256] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nharness-admission-lane <lanes>\nharness-assert-gates <gate>...\ngha-collaborator-trust <owner/repo> [--allow-bot <login>]... < authors.json\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\nlink-skill <name> --source-root <skills-dir> --target-root <consumer-skills-dir> Link a packaged or repository-local skill\nretrospective-facts (--pr NUMBER | --branch NAME | --no-pr) [--repo OWNER/NAME] [--raw]\nagent-blackboard probe\nagent-blackboard journal append --mode interactive|autonomous --source-event-id ID --work-outcome OUTCOME --coverage-status STATUS --session-id UUID --agent NAME --version VERSION --file PATH --repository OWNER/NAME [--repository OWNER/NAME ...] [--parent-session-id UUID] [--timestamp ISO8601] [--coverage-source SOURCE,...] [--dropped-count N] [--outbox-directory PATH]\nagent-blackboard journal entries --session-id UUID\nagent-blackboard journal status --session-id UUID --outbox-directory PATH\nagent-blackboard journal flush --outbox-directory PATH [--session-id UUID]\nInteractive journal append requires --outbox-directory PATH.\nagent-blackboard journal is deprecated and being phased out: agents journal through the mcp server.\nagent-blackboard snapshot partition --snapshot PATH --checksum SHA256 --counts '{\"sessions\":N,\"entries\":N,\"records\":N,\"bytes\":N}'\nagent-blackboard snapshot cleanup [--snapshot PATH] [--partition-directory PATH --receipt JSON]\nmcp\n (no args) Serve journal_append, journal_entries, outbox_status, outbox_flush,\n session_ensure, snapshot_export, and session_archive over stdio.\n Needs the optional @modelcontextprotocol/sdk peer (and zod).\n Launch it from inside the repository's git worktree.\n";
2
2
  export declare function printUsage(stream?: NodeJS.WritableStream): void;
3
3
  export declare function commandNames(usage?: string): string[];
4
4
  export declare function commandUsage(command: string, usage?: string): string;
@@ -121,6 +121,7 @@ agent-blackboard journal entries --session-id UUID
121
121
  agent-blackboard journal status --session-id UUID --outbox-directory PATH
122
122
  agent-blackboard journal flush --outbox-directory PATH [--session-id UUID]
123
123
  Interactive journal append requires --outbox-directory PATH.
124
+ agent-blackboard journal is deprecated and being phased out: agents journal through the mcp server.
124
125
  agent-blackboard snapshot partition --snapshot PATH --checksum SHA256 --counts '{"sessions":N,"entries":N,"records":N,"bytes":N}'
125
126
  agent-blackboard snapshot cleanup [--snapshot PATH] [--partition-directory PATH --receipt JSON]
126
127
  mcp
@@ -4,9 +4,6 @@ export interface DirectoryIdentity {
4
4
  readonly mode: number;
5
5
  readonly uid: number;
6
6
  }
7
- /** pnpm's cache directory. The audit store stays beside it so it is not the developer store. */
8
- export declare function pnpmCacheDirectory(env?: NodeJS.ProcessEnv, home?: string, hostPlatform?: NodeJS.Platform): string;
9
- export declare function licenseAuditStoreDirectory(env?: NodeJS.ProcessEnv, home?: string, hostPlatform?: NodeJS.Platform): string;
10
7
  export declare function assertOwnedDirectory(stat: DirectoryIdentity, uid: number | undefined, directory: string): void;
11
- /** Creates the dedicated content-addressed store used by repeat license audits. */
8
+ /** Creates the private, per-run store beneath the disposable license audit workspace. */
12
9
  export declare function ensurePrivateLicenseAuditStore(directory: string): void;
@@ -1,19 +1,4 @@
1
1
  import { chmodSync, lstatSync, mkdirSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { join } from 'node:path';
4
- const STORE_DIRECTORY_NAME = 'dependency-license-audit-store';
5
- /** pnpm's cache directory. The audit store stays beside it so it is not the developer store. */
6
- export function pnpmCacheDirectory(env = process.env, home = homedir(), hostPlatform = process.platform) {
7
- if (hostPlatform === 'darwin')
8
- return join(home, 'Library', 'Caches', 'pnpm');
9
- if (hostPlatform === 'win32') {
10
- return join(env.LOCALAPPDATA ?? join(home, 'AppData', 'Local'), 'pnpm-cache');
11
- }
12
- return join(env.XDG_CACHE_HOME ?? join(home, '.cache'), 'pnpm');
13
- }
14
- export function licenseAuditStoreDirectory(env = process.env, home = homedir(), hostPlatform = process.platform) {
15
- return join(pnpmCacheDirectory(env, home, hostPlatform), STORE_DIRECTORY_NAME);
16
- }
17
2
  export function assertOwnedDirectory(stat, uid, directory) {
18
3
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
19
4
  throw new Error(`dependency license audit store is not a real directory: ${directory}`);
@@ -22,7 +7,7 @@ export function assertOwnedDirectory(stat, uid, directory) {
22
7
  throw new Error(`dependency license audit store is not owned by the current user: ${directory}`);
23
8
  }
24
9
  }
25
- /** Creates the dedicated content-addressed store used by repeat license audits. */
10
+ /** Creates the private, per-run store beneath the disposable license audit workspace. */
26
11
  export function ensurePrivateLicenseAuditStore(directory) {
27
12
  mkdirSync(directory, { recursive: true, mode: 0o700 });
28
13
  const stat = lstatSync(directory);
@@ -5,7 +5,6 @@ export interface CollectPnpmLicenseReportOptions {
5
5
  readonly execute?: PnpmExecutor;
6
6
  readonly prepareWorkspace?: (repoRoot: string, lockfileSource: string, workspaceSource: string) => PnpmLicenseAuditWorkspace;
7
7
  readonly readFile?: (path: string, encoding: 'utf8') => string;
8
- readonly storeDir?: string;
9
8
  }
10
9
  /** Collects licenses for every platform represented in a pnpm lockfile. */
11
10
  export declare function collectPnpmLicenseReport(repoRoot: string, options?: CollectPnpmLicenseReportOptions): Promise<PnpmLicenseReport>;
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { withAuditSignalCleanup } from "./audit-signals.mjs";
4
- import { ensurePrivateLicenseAuditStore, licenseAuditStoreDirectory } from "./audit-store.mjs";
4
+ import { ensurePrivateLicenseAuditStore } from "./audit-store.mjs";
5
5
  import { executePnpm } from "./execute-pnpm.mjs";
6
6
  import { parsePnpmLicenseReport } from "./report.mjs";
7
7
  import { preparePnpmLicenseAuditWorkspace } from "./workspace.mjs";
@@ -25,7 +25,7 @@ function assertCommandSucceeded(label, result) {
25
25
  export async function collectPnpmLicenseReport(repoRoot, options = {}) {
26
26
  const { ensureStore, execute, prepareWorkspace, readFile } = { ...DEFAULT_OPTIONS, ...options };
27
27
  const auditWorkspace = prepareWorkspace(repoRoot, readFile(join(repoRoot, 'pnpm-lock.yaml'), 'utf8'), readFile(join(repoRoot, 'pnpm-workspace.yaml'), 'utf8'));
28
- const storeDir = options.storeDir ?? licenseAuditStoreDirectory();
28
+ const storeDir = join(auditWorkspace.cwd, 'store');
29
29
  return withAuditSignalCleanup(auditWorkspace.cleanup, async (signal) => {
30
30
  ensureStore(storeDir);
31
31
  const storeConfig = `--config.store-dir=${storeDir}`;
@@ -11,7 +11,7 @@ type GeneratedArbiterRoot = {
11
11
  kind: 'parenthesized';
12
12
  expression: GeneratedArbiterRoot;
13
13
  } | {
14
- kind: 'functionCall' | 'cast' | 'nullTest' | 'distinctness' | 'parameter' | 'typedLiteral' | 'literal' | 'binary' | 'unary' | 'case' | 'subquery' | 'other';
14
+ kind: 'functionCall' | 'cast' | 'nullTest' | 'distinctness' | 'parameter' | 'typedLiteral' | 'literal' | 'binary' | 'unary' | 'array' | 'case' | 'subquery' | 'other';
15
15
  };
16
16
  export type GeneratedArbiterExpression = {
17
17
  columns: readonly GeneratedArbiterName[];
@@ -40,8 +40,10 @@ environment. The server never searches for, prints, or mints them.
40
40
 
41
41
  ## CLI fallback
42
42
 
43
- If MCP is unavailable, use `vouchington agent-blackboard journal append|entries|flush|status` as described
44
- in the blackboard skill. Record the fallback and delivery status in the journal and tell the human. The CLI resolves its
43
+ MCP is the supported path. If it is unavailable, restore it first as the blackboard skill describes.
44
+ As a last resort, use `vouchington agent-blackboard journal append|entries|flush|status` as described
45
+ there; sandboxed Claude Code and Codex withhold the token, so it can only retain records in the
46
+ outbox the server later flushes. Record the fallback and delivery status in the journal and tell the human. The CLI resolves its
45
47
  client from its own installation, so install `agent-blackboard` alongside that trusted CLI.
46
48
  Run the script with a verified absolute `node` and a cleared environment (`env -i`), never through
47
49
  its `#!/usr/bin/env node` line, which takes `node` from a possibly repository-controlled `PATH`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.40.0",
3
+ "version": "0.41.0",
4
4
  "description": "Vouchington CLI and extractable tooling libraries.",
5
5
  "homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
6
6
  "bugs": {
@@ -377,7 +377,7 @@
377
377
  },
378
378
  "devDependencies": {
379
379
  "@ast-grep/cli": "0.45.3",
380
- "@modelcontextprotocol/sdk": "1.31.0",
380
+ "@modelcontextprotocol/sdk": "1.32.0",
381
381
  "@types/picomatch": "^4.0.3",
382
382
  "@types/spdx-expression-parse": "4.0.0",
383
383
  "agent-blackboard": "^0.6.1",
@@ -38,18 +38,36 @@ Every call may take `worktree`, the absolute path of a worktree of the current r
38
38
  launch worktree by default). Writing or retrying an entry needs no provider skill, temporary file,
39
39
  `--file` flag, or replay command.
40
40
  Search for `journal_append` (by bare name, so every prefix matches) before concluding the server is
41
- unavailable; a deferred harness lists the tool only on request. If the search finds no such tool
42
- because the server is not registered or not connected, use the supported CLI fallback below.
43
- Tell the human that MCP is unavailable and which CLI is being used. Record the fallback reason,
44
- entrypoint, affected operations, and observed delivery status in the caller's journal before
45
- continuing primary work. Do not treat a permission denial as tool unavailability or bypass a host
46
- approval requirement through the CLI. If neither path persists the note, stop and report the blocker.
41
+ unavailable; a deferred harness lists the tool only on request. A tool error is not
42
+ unavailability: act on its message and retry through MCP.
43
+
44
+ ## When the server is unavailable
45
+
46
+ MCP is the supported journaling path. If the search finds no such tool, stop journaling and tell the
47
+ human which case applies before continuing:
48
+
49
+ - Not registered: the machine's agent configuration must register it; follow the consumer's
50
+ registration and diagnosis steps.
51
+ - Registered but disconnected: reconnect it through the harness's MCP controls, or restart the
52
+ harness.
53
+ - Automated runs with no human to ask: report "journaling unavailable" in the final report.
54
+
55
+ Prefer restoring MCP over the CLI fallback below, and use the fallback only when the human asks or
56
+ MCP cannot be restored for this session. Harness sandboxes commonly withhold
57
+ `AGENT_BLACKBOARD_TOKEN` from shell commands, so the fallback usually cannot deliver there. Never
58
+ request an unsandboxed run only to obtain the token. When the fallback is used, record its reason,
59
+ entrypoint, affected operations, and observed delivery status in the caller's journal. Do not treat
60
+ a permission denial as tool unavailability or bypass a host approval requirement through the CLI.
61
+ If neither path persists the note, stop and report the blocker.
47
62
 
48
63
  ## CLI fallback
49
64
 
65
+ Deprecated and being phased out: the MCP tools replace it, and retrospective and PR writers are
66
+ moving to MCP tools as well.
67
+
50
68
  Use a trusted machine-installed `vouchington` executable at a verified absolute path outside the
51
69
  consumer worktree. Resolve its symlinks and verify the installation's source and version before
52
- using credentials or requesting an unsandboxed run; its runtime dependencies must also belong to
70
+ using credentials; its runtime dependencies must also belong to
53
71
  that trusted installation. The CLI resolves its client relative to its own installation; installing
54
72
  `agent-blackboard` only in the consumer worktree is insufficient for CLI fallback. Do not resolve the executable through the consumer's `node_modules/.bin`,
55
73
  `pnpm exec`, or repository-controlled `PATH`. Set `BLACKBOARD_CLI` below to that verified absolute
@@ -93,13 +111,9 @@ explicit coverage sources when assessed. Omit `--timestamp` so the writer owns t
93
111
  mode omits `--outbox-directory` and still requires fresh online admission plus readback.
94
112
  For session-only or snapshot operations not exposed by this CLI, use the upstream
95
113
  `agent-blackboard` CLI under its skill's operation contract; preserve exact identities and tags.
96
- A sandboxed fallback may only write the outbox: the machine's harness sandbox can withhold
97
- `AGENT_BLACKBOARD_TOKEN`, so it cannot deliver or read back. If delivery or readback needs the
98
- credentials and the sandbox withholds them, run that one command unsandboxed through the harness's
99
- normal approval path for running one command outside the sandbox, with each such run approved
100
- individually. Never read, print, copy, or export the token
101
- to work around the sandbox. If approval is denied, leave the record pending in the outbox, report
102
- `pendingCount`, and tell the human.
114
+ A sandboxed fallback may only write the outbox: without `AGENT_BLACKBOARD_TOKEN` it cannot deliver
115
+ or read back. Leave the record pending, report `pendingCount`, and deliver it with `outbox_flush`
116
+ once MCP is restored. Never read, print, copy, or export the token to work around the sandbox.
103
117
  Return to MCP when available and journal recovery. Never silently downgrade envelope validation,
104
118
  retention, or delivery checks because the transport changed.
105
119
 
@@ -24,7 +24,7 @@
24
24
  {
25
25
  "name": "bounded-iteration",
26
26
  "plugin": "vouchington-database",
27
- "pluginVersion": "0.5.0",
27
+ "pluginVersion": "0.6.0",
28
28
  "path": "bounded-iteration/SKILL.md"
29
29
  },
30
30
  {
@@ -109,19 +109,19 @@
109
109
  {
110
110
  "name": "postgres-node-performance-tuning",
111
111
  "plugin": "vouchington-database",
112
- "pluginVersion": "0.5.0",
112
+ "pluginVersion": "0.6.0",
113
113
  "path": "postgres-node-performance-tuning/SKILL.md"
114
114
  },
115
115
  {
116
116
  "name": "postgres-partitioning-uuid-v7",
117
117
  "plugin": "vouchington-database",
118
- "pluginVersion": "0.5.0",
118
+ "pluginVersion": "0.6.0",
119
119
  "path": "postgres-partitioning-uuid-v7/SKILL.md"
120
120
  },
121
121
  {
122
122
  "name": "postgres-schema-design",
123
123
  "plugin": "vouchington-database",
124
- "pluginVersion": "0.5.0",
124
+ "pluginVersion": "0.6.0",
125
125
  "path": "postgres-schema-design/SKILL.md"
126
126
  },
127
127
  {
@@ -18,6 +18,8 @@ Measure the query plan and the workload shape before changing code.
18
18
  - Keep connection-pool usage bounded.
19
19
  - Validate a query change at representative cardinality. Watch latency, memory, lock time, and
20
20
  connection pressure together.
21
+ - Cut round trips: fold dependent reads, batch per-item lookups, and overlap independent reads; see
22
+ [round trips](references/performance-patterns.md#round-trips).
21
23
  - Read [performance patterns](references/performance-patterns.md) before changing a high-volume
22
24
  path.
23
25
 
@@ -37,3 +37,26 @@ recipient-keyed fan-out rows. Verify actual pruning with EXPLAIN.
37
37
 
38
38
  Generic `jonathanong/no-mistakes` checks include `postgres-no-offset`; inspect available rules
39
39
  and configure reviewed cross-partition exceptions rather than treating a rule as plan evidence.
40
+
41
+ ## Round trips
42
+
43
+ Sequential queries can add network round trips when the client waits between statements, and planning
44
+ can add latency when PostgreSQL does not reuse a prepared plan; count round trips per request before
45
+ tuning individual statements.
46
+
47
+ Load a parent and the viewer's relation to it in one query: join the membership row, or use a
48
+ lateral subquery, rather than reading the parent and then the relation.
49
+
50
+ `Promise.all` over statements on one transaction client is still serial, because one connection
51
+ runs one statement at a time. Merge them instead: CTEs, `UNNEST`, or one multi-row statement.
52
+
53
+ Give every per-item lookup helper a batch twin that takes an array of keys and returns a keyed
54
+ map, and call the twin from loops, `.map` callbacks, and `Promise.all` fan-outs. `no-await-in-loop`
55
+ misses a helper that queries internally and `Promise.all(items.map(helper))`; review those call
56
+ sites by hand.
57
+
58
+ Overlap independent cache and PostgreSQL reads with `Promise.all`, such as a rate-limiter check
59
+ alongside the user fetch. Serialize only true dependencies, where one result feeds the next call.
60
+
61
+ Run a symmetric check, such as "is either party blocking the other", as one query with an `OR`
62
+ or both-direction predicate, not twice with the arguments swapped.