Repository navigation
Releases
Releases · AnonZ7/fact-gate
fact-gate 1.2.0 — git pre-commit mode, sticky PR comment
Where it runs, part two: git and the PR conversation. Chosen after a second
round of adversarial review of the roadmap, which dropped an MCP server and
a browser playground (no evidence either channel produces users for a CI
tool) in favour of the two things every team already has.
Added
fact-gate pre-commit. Checks the staged content (git show :path)
of every file the nearest.fact-gate.jsoncovers, refuses the commit on
a contradiction. Editor-agnostic: Cursor, Codex, Copilot and humans go
through the same gate..pre-commit-hooks.yamlfor the pre-commit
framework; husky and lefthook one-liners in the README.checkStaged,
stagedPaths,stagedContentin the library.- Sticky PR comment.
comment: 'true'on the Action posts one comment
with the report and keeps it updated on every push (pull-requests: write).
The Action now records its exit code and fails in a final step, so the
comment is posted even when the gate blocks. fact-gate/core: the browser-safe half of the library (no Node built-ins).
Deferred, deliberately
MCP server, GitHub Pages playground, SARIF output, dedicated JUnit / lcov /
git-log adapters. The cmd measurement already covers any artefact a shell
can read; the rest will be built when a user asks.
fact-gate 1.1.0 — PR descriptions vs the diff, measured facts, GitHub Action, Claude Code hook
The gate moves from "run it by hand on a CV" to "it runs where the text is
written". Same engine, three new places it fires, and three new kinds of
truth it can check against.
Added
- A diff is a source of truth.
--diff <file>/--git <base>/
verifyFacts(text, { diff })turn a unified diff (orgit diff --numstat)
into facts: files by status, lines by direction, test cases added,
dependencies added or removed (npm, pip, go.mod, Cargo). A PR description
is verified against the change it describes.parseDiff,factsFromDiff. - Measured facts. Any value in a facts file may be
{"cmd"|"file"|"json", "pattern"}and is resolved at check time, so the README is checked against
the test suite's own output, not against a number someone typed last month.
fact-gate measure,resolveFacts,measure. A measurement that fails is
an error, never a silent skip. - GitHub Action.
uses: AnonZ7/fact-gate@v1checks the PR body against
the PR diff (default) or any file against facts/source; annotations, a
step summary with the measured facts, andverdict/reportoutputs. - Claude Code hook.
fact-gate hookas a PreToolUse hook on Write / Edit
/ MultiEdit denies a save whose numbers contradict.fact-gate.jsonand
hands the reasons back to the agent.fact-gate initscaffolds the config
and prints the settings snippet. Inert when no config is found; never
breaks a session. - Extraction: verbs qualify a count (
adds 4 tests→ tests/added);
participles after the noun (6 lines deleted); floors from words (over 4,000,more than 30,at least 5); approximate claims (roughly 500,
about 5k,~85) judged with a 10% tolerance; spelled-out small counts
(two new files) andnoin a change context (no new dependencies= 0
added); colon breakdowns (6 files: 2 new, 1 deleted, 3 modified);
qualified noun-first forms (hook files: 27); singular nouns (1 dependency); a code-change vocabulary (files, insertions, deletions,
dependencies, packages, functions, …). - Comparison: a qualified claim is judged by the source entries that share
its qualifier before the generous number-only match applies, sono new dependenciesmeetsdependencies added: 1and loses instead of meeting
dependencies deleted: 0and winning. Contradiction messages name the
best-matching figure with its qualifiers. - Output:
--format markdown(table for PR comments),--format github
(annotations +$GITHUB_STEP_SUMMARY+$GITHUB_OUTPUT), colour on a TTY,
--target-env,--no-measure,--no-color. - Evals: three suites (CV vs profile, PR body vs diff, docs vs facts)
with per-suite precision and recall, so a weak domain cannot hide in the
average.evals/run.mjs --json. - JSON Schema for
.fact-gate.json;mergeFacts; TypeScript declarations
for everything above. - The repository gates its own README with itself
(.github/workflows/fact-gate.yml,.fact-gate.json). - Trust model for command measurements. In hook mode a config's
cmd
measurements run only afterfact-gate trust <config>has recorded the
file's hash in~/.fact-gate/trusted.json(or withFACT_GATE_ALLOW_CMD=1
in CI). Until then literal,fileandjsonfacts still gate, and the
agent is told why the command was skipped. Editing the config revokes trust. - Negated counts (
does not touch 12 files,doesn't add 40 tests,
without adding 300 lines) are not claims of that count. - Fullwidth and Arabic-Indic digits normalise to ASCII before extraction.
- Unknown
--flagsare a usage error (exit 2) instead of being ignored.
Fixed
- Hook ordering (pre-release review, critical): the include/exclude filter
now runs before anything in the config is loaded, so a write to a file the
config does not cover runs nothing from the config. Pinned by
test/security.test.mjs. - A heading on the line above a
Tests: 999claim was captured as a
qualifier, turning a fabrication into a warning. Noun-first qualifiers must
now sit on the same line; line breaks survive normalisation. - An
Editwhoseold_stringis absent from the file is skipped instead of
being judged against the unmodified file. - A currency amount followed by a noun (
$90,000 deal) was also read as a
count once singular nouns entered the vocabulary. Counts now refuse a
currency prefix. total/overall/combinedare vacuous qualifiers and no longer make
total tests: 900incomparable withtests: 846.
Changed
contradicts()is kept;contradictions()returns the ranked entries the
messages are built from.