Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,57 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

Fixes for the two findings of the 2026-09-27 recheck of v1.7.3 (Q01, Q02). The recheck
confirmed that all eight N01–N08 reproduction cases are closed; its scripts
(`reproduce_remaining.mjs`, `original-reproduce.mjs` and `edge-probes.mjs`, each with
`--assert-fixed`) all pass.

### Fixed

- **A local program named like a package manager no longer covers the workspaces (Q02).** A
root `test` script of `./tools/npm test --workspaces` was credited as npm's recursive run
because the recognizer read only the file's basename, so a stub that exited 0 hid a failing
workspace behind a PASS. A tool is now recognized only by its bare name (the program the
script's PATH finds) or as its own install under `node_modules/.bin`. Any other path, such as
`./tools/npm`, `./scripts/pnpm.js` or `/usr/bin/env`, is an unknown program whatever its
name, so the members run on their own. `forge verify` reports the root run as "not credited"
and names the program.
- A command line may set only variables known to change neither the program nor the run
(`CI`, `NODE_ENV`, `FORCE_COLOR`, `NODE_OPTIONS` with memory or warning flags…). `PATH`,
`LD_PRELOAD`, `HOME`, a `NODE_OPTIONS` preload and any other variable keep the run from
being credited.
- Wrapper options that pick the binary, the directory or the environment are refused:
`npx -p`/`--package`, `env -i`, `env -C`/`--chdir`, and options on `cross-env`.
- A bare name must not be shadowed. The first `node_modules/.bin` entry on the script's PATH
(the package's own, then each parent directory's) must be the tool's own package's binary,
and a symlink must resolve into that package. A package manager or system program there is
a shim. On Windows, a same-named executable in the package root (`npm.cmd`) runs first, so
it counts as a shadow too.
- yarn must be a release: a `yarnPath` (or yarn 1's `yarn-path`) outside `.yarn/releases/`,
or a `packageManager` that fetches the manager from a URL, is refused.
- `.npmrc` and environment `node-options` must be inert, a `script-shell` that is a program
inside the project is not a shell, and nx plugins, which can redefine each project's `test`
target, make nx and lerna runs run the members on their own.
- A `verify.workspaces: "root"` declaration still covers every member and is still labelled
`declared`.
- **A near reuse hit is no longer presented as the same task (Q01).** "Deny admins and allow
guests…" near-hit an artifact verified for "Allow admins and deny guests…" (MinHash 0.83),
and the CLI called it a "reworded match".
- Every hit now says what it establishes. `semanticEquivalence` is `"identical"` for an
exact hit (the byte-identical spec) and `"unverified"` for near and adapt, and
`requiresReview` is `true` for every non-exact hit. `forge reuse query --json` and the gate's
reuse summary carry both fields, and the CLI and gate describe a near hit as "a similar
task, equivalence unverified".
- The semantic guard adds a `binding` conflict kind. Each polarity, negation or direction
word binds to the next content word of its clause. Two texts conflict when a word both bind
is bound to opposite relations (allow→admins vs deny→admins, from→staging vs to→staging), or
when they use exactly the same words in a different order. Permission-subject swaps,
source/destination swaps and role swaps are therefore held at `adapt`. Consolidation and
compaction list such pairs as conflicts rather than proposals.
- **The claims check no longer fails in a checkout that lacks newer release tags.** A claim
naming a release newer than every local tag, and not newer than `package.json`'s version, is
reported as unchecked, with a hint to run `git fetch --tags`, instead of failing the check.

## [1.7.3] - 2026-09-27

Fixes for the eight findings of the 2026-09-27 follow-up review (N01–N08) and its suggestions.
Expand Down
44 changes: 34 additions & 10 deletions docs/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -705,11 +705,24 @@ conservative too:
- Options are allowlisted per tool. An unknown one (`--help`, `--dry-run`, an abbreviation
npm would expand) is not credited, and neither are words after `--`, which are forwarded
into every member's script.
- A script that changes shell state (`cd`, `exit`, `trap`, `export`…) or sets a
package-tool variable (`npm_config_*`) is not credited.
- A tool is recognized by its bare name, the program the script's PATH finds, or as its own
install under `node_modules/.bin`. Any other path (`./tools/npm`, `./scripts/pnpm.js`,
`/usr/bin/env`) is an unknown program whatever its name, and is never credited.
- A script that changes shell state (`cd`, `exit`, `trap`, `export`…) is not credited, and
the command may set only variables known to change neither the program nor the run (`CI`,
`NODE_ENV`, `FORCE_COLOR`, `NODE_OPTIONS` with memory or warning flags, the cache-bypass
variables…). `PATH`, `LD_PRELOAD`, `HOME`, `npm_config_*` and anything else are refused, and
so are wrapper options that pick the binary or the directory (`npx -p`, `env -C`).
- A bare name must not be shadowed. The first `node_modules/.bin` entry on the script's PATH
(the package's own, then each parent directory's) must be the binary of the tool's own
installed package, and a symlink must resolve into it. A copy of a package manager or a
system program there is a shim. A same-named executable in the package root (`npm.cmd`)
counts too, because Windows runs it first. yarn must be a release: a `yarnPath` outside
`.yarn/releases/`, or a `packageManager` fetched from a URL, is refused.
- Configuration that narrows the run is honoured: `.npmrc` or environment
`workspace`/`filter`/`script-shell`, lerna `command.run` filters, `.nxignore`, a
redefined nx `test` target, and turbo per-package tasks.
`workspace`/`filter`/`script-shell`, a `node-options` that loads code, lerna `command.run`
filters, `.nxignore`, a redefined nx `test` target or nx plugins (which can define it), and
turbo per-package tasks.
- A cached result is not a run: turbo needs `--force` (or `cache: false` for `test`), and nx
and lerna need `--skip-nx-cache`.
- Only members of that tool's own workspace list count, read for the package manager in use.
Expand All @@ -718,11 +731,11 @@ conservative too:

The `coverage basis` line says what each package's verdict rests on: `measured` (its own
suite ran), `inferred` (the recognized root command) or `declared` (`workspaces: "root"`). A
recognized root command that was not credited is printed as `root run not credited`, with the
reason. forge trusts the repository's own tooling: a shim that replaces the package manager
or the test runner is outside what it checks (one in `node_modules/.bin` shadowing
npm/pnpm/yarn is refused). A `script-shell` that is not a shell (`/bin/true`) makes npm and
pnpm suites `INCOMPLETE`. Fixture and test-data packages are never required. A test runner
root command that was not credited, including one that names a program by its path, is
printed as `root run not credited`, with the reason. Beyond these checks forge trusts the
installed tools themselves: it does not audit what a genuine package's binary or the test
runner does. A `script-shell` that is not a shell (`/bin/true`), or that is a program inside
the project, makes npm and pnpm suites `INCOMPLETE`. Fixture and test-data packages are never required. A test runner
that is only a devDependency is not an obligation either; `forge stack` lists it as
`available`.
Tune this per repo under `verify` in `.forge/forge.config.json`:
Expand Down Expand Up @@ -1170,10 +1183,20 @@ unchanged.
never share a key. Artifacts minted before key version 3 never hit exact. Inline code the
ledger's storage would rewrite (CRLF line endings, non-NFC text) is refused at mint; mint
it from a file instead.
- **Near must also agree on behaviour.** A reworded match is offered as `near` only when the
- **Only exact establishes the same task.** Every hit carries `semanticEquivalence`:
`"identical"` for an exact hit, `"unverified"` for near and adapt. It also carries
`requiresReview`, `true` for every non-exact hit. A near hit is a similar task that no check
has shown to mean the same thing: review it against yours before reusing it.
`revalidation` answers a different question, namely whether the artifact and its
dependencies still hold.
- **Near must also agree on behaviour.** A similar spec is offered as `near` only when the
two specs agree, in the same order, on these:
- operators and symbols, with their operands (`x + 1` vs `x - 1`, `a - b` vs `b - a`);
- numbers, identifiers, paths and negation;
- what each polarity, negation or direction word applies to. "Allow admins and deny
guests" vs "Deny admins and allow guests", or "from staging to production" vs "from
production to staging", conflict on `binding`, and so does the same set of words in a
different order;
- literals, typographic and backtick quotes included (“a b”, ``a b``);
- every whitespace run other than one space (line breaks, indentation, tabs, CRLF, columns);
- spelling (`parse` vs `Parse`, fullwidth or Cyrillic look-alikes) and invisible format
Expand Down Expand Up @@ -1203,6 +1226,7 @@ $ forge reuse query "debounce user input before firing search"
sim: minhash
NEAR hit (similarity 0.87) — module at src/lib/debounce.js
claim 9c41d2ab77e0 — `forge ledger blame 9c41d2ab` for its proof
near tier: a similar task, equivalence unverified — review it against yours before reusing

$ forge reuse query "quantum blockchain"
sim: minhash
Expand Down
7 changes: 6 additions & 1 deletion docs/plans/substrate-v2/03-reuse-cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ neighbourhood" are different questions:
exact tier now compares `keyHash`, a digest of the text's code units, and nothing is
normalized at that boundary; similarity search stays layout-blind. The near tier compares
the stored `key` with the semantic guard, so it requires a key of the current version
that the ledger stored verbatim (`keyVerbatim`: no CRLF or non-NFC text to fold).
that the ledger stored verbatim (`keyVerbatim`: no CRLF or non-NFC text to fold). The
guard's `binding` kind (review Q01) also compares what each polarity or direction word
applies to, so "Allow admins and deny guests" and "Deny admins and allow guests", which
share every token, are held at adapt. No token check establishes that two texts mean the
same, so every hit states what it establishes: `semanticEquivalence` is `"identical"` only
for exact and `"unverified"` for near and adapt, which also carry `requiresReview: true`.
- **shape** (`spec`): identity plus typed placeholders for identifiers, paths, numbers and
string literals (`⟨ident⟩`, `⟨path⟩`, `⟨num⟩`, `⟨str⟩`).

Expand Down
Loading
Loading