You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three README claims describe engine or repository behaviour that rootline 9.12.1 does not implement, and — checked against git history — never implemented on any commit:
README
Claim
Reality
README.md:373
the .githooks/pre-commit hook runs validate --staged automatically
the hook runs gofmt, golangci-lint and gitleaks; the string validate --staged appears in no hook, workflow or Justfile recipe
README.md:375
Rootline's graph analyzer can detect when .stem file changes conflict with document mutations
no merge-conflict capability exists anywhere in the tree, and git log -S proves none ever did
README.md:393
a field present in ≥80% of records is required
the comparison is strictly > (internal/infer/infer.go:113); at exactly 80% nothing is inferred
They are grouped here because they share one root cause and one fix. The root cause is that README's narrative sections were written from intent rather than re-derived from the engine — the two integration bullets landed together in e3214c2 (2026-07-22, docs(readme), README-only, +30 lines) whose own message asserts "All sections verified against current source and existing workflows", and the threshold sentence landed in 4eccab8 (2026-06-24, also docs-only). Neither claim was true at the commit that introduced it. The fix is one README pass over three lines.
Classification: documentation drift. In all three cases the binary and the repository are behaving deliberately and the sibling documentation is already correct — docs/analyze.md:51 and docs/analyze.md:107 both state >80%, and the CLI's own inference message (cmd/rootline/analyze.go:204) says appears in >80% of records — required. Only README.md is wrong.
It matters because README is the first surface an agent reads to decide what Rootline can do. An agent that believes 373 will not install a documented validation gate that does not exist; one that believes 375 will look for a graph subcommand it can never find; one that believes 393 will file a bug when a field at exactly 80% is not marked required, or will hand-write a .stem on a threshold the engine does not use.
Steps to Reproduce
1. README.md:373 — the pre-commit hook does not run validate --staged
README.md:373 claims:
Staged validation — The .githooks/pre-commit hook runs validate --staged automatically, catching schema violations before commit
The hook, in full, from a clean checkout at 7d95e35:
$ cat .githooks/pre-commit#!/usr/bin/env bash
# Pre-commit: format check, lint, and secret scanecho "Running gofmt check..."UNFORMATTED=$(gofmt -l . 2>/dev/null | grep -v vendor || true)...echo "Running golangci-lint..."if command -v golangci-lint &>/dev/null; then golangci-lint run...
# Scan staged changes for secretsif command -v gitleaks &>/dev/null; then gitleaks git --pre-commit --staged
--staged on line 23 belongs to gitleaks, not to rootline. Nothing in the repository invokes the flag:
The --staged flag itself is real (rootline validate --help lists --staged validate only files in git staging area) — what does not exist is the hook wiring README describes. The sibling bullet README.md:374 is accurate: .github/workflows/ci.yml:38 really does run ./rootline validate --all docs/roadmap/.
2. README.md:375 — no merge-conflict analysis exists on any graph surface
README.md:375 claims:
Merge conflict detection — Rootline's graph analyzer can detect when .stem file changes conflict with document mutations
The whole graph surface:
$ rootline graph --helpFlags: --check validate only (cycles + broken links), no diagram --fail-cycles treat cycles as check failures (overrides .stem links.checks.cycles) --format string diagram format when -o table: dot or mermaid (default "dot") -h, --help help for graph --quiet-cycles suppress per-cycle enumeration when informational --where stringArray filter expression (e.g. "tipo != 'feature'")
No such capability exists in the tree, and none ever did:
README.md:375 is the only occurrence of the phrase in the repository — no code, no test, no other doc page.
The nearest real thing is unrelated on both halves of the claim: internal/rules/resolver.go:180ResolveLayered(path, root, monotonic) populates a Conflicts slice, but it compares one .stem layer against another .stem layer — never .stem against document mutations — and its only CLI reach is the monotonic-violations stem-health check inside validate --all (internal/rules/stemhealth.go:389). It is not the graph analyzer and it is not merge-conflict detection.
3. README.md:393 — the required threshold is strictly greater than 80%
README.md:392-393 claims:
Rootline's engine decides everything resolvable from form — frequency
thresholds (a field present in ≥80% of records is required) [...]
Fixture
Built from scratch in an empty scratch directory. A version 2.stem — a stem carrying only root: true is version 0 and is rejected before inference or validation ever runs, so it would prove nothing:
Five records. owner is present in exactly four of them, which is exactly 80%. One record (control.md) deliberately omits the required titulo so the run carries a control error:
r1.md, r2.md, r3.md -> titulo + owner
control.md -> owner only (deliberately missing required titulo)
r5.md -> titulo only
Proof the fixture reaches real validation rather than stem-version rejection — the control error fired with the .stem as its source, and both stem_health and notices are empty:
4eccab8 is the commit that wrote ≥80% into README; at that same commit the comparison was already >. The comparison has never been >= on any commit.
Worth noting that the exact-80% case is not silent — validation_gaps reports required_understatement there, gated at >= 0.80 (internal/infer/validation_gaps.go:11). The two detectors are complementary by design; it is only README that names the wrong operator for the one that infers required.
Expected Behavior
README.md describes what the shipped engine and the shipped hooks do, so that a reader who acts on it is not chasing a hook, a subcommand, or a threshold boundary that does not exist.
Actual Behavior
README.md:373 describes a .githooks/pre-commit step that does not exist; the string validate --staged appears nowhere in the repository.
README.md:375 describes a graph capability with no code, no test, no flag and no other mention anywhere in the tree, on any commit.
README.md:393 states ≥80% where the engine, its own inference message, and docs/analyze.md:51,107 all say >80%; at exactly 80% nothing is inferred.
Environment
Rootline version: rootline version 9.12.1 (equal to origin/master at 7d95e35)
Description
Three README claims describe engine or repository behaviour that
rootline9.12.1 does not implement, and — checked against git history — never implemented on any commit:README.md:373.githooks/pre-commithook runsvalidate --stagedautomaticallygofmt,golangci-lintandgitleaks; the stringvalidate --stagedappears in no hook, workflow orJustfilerecipeREADME.md:375.stemfile changes conflict with document mutationsgit log -Sproves none ever didREADME.md:393required>(internal/infer/infer.go:113); at exactly 80% nothing is inferredThey are grouped here because they share one root cause and one fix. The root cause is that README's narrative sections were written from intent rather than re-derived from the engine — the two integration bullets landed together in
e3214c2(2026-07-22,docs(readme), README-only, +30 lines) whose own message asserts "All sections verified against current source and existing workflows", and the threshold sentence landed in4eccab8(2026-06-24, also docs-only). Neither claim was true at the commit that introduced it. The fix is one README pass over three lines.Classification: documentation drift. In all three cases the binary and the repository are behaving deliberately and the sibling documentation is already correct —
docs/analyze.md:51anddocs/analyze.md:107both state>80%, and the CLI's own inference message (cmd/rootline/analyze.go:204) saysappears in >80% of records — required. OnlyREADME.mdis wrong.It matters because README is the first surface an agent reads to decide what Rootline can do. An agent that believes 373 will not install a documented validation gate that does not exist; one that believes 375 will look for a
graphsubcommand it can never find; one that believes 393 will file a bug when a field at exactly 80% is not marked required, or will hand-write a.stemon a threshold the engine does not use.Steps to Reproduce
1.
README.md:373— the pre-commit hook does not runvalidate --stagedREADME.md:373claims:The hook, in full, from a clean checkout at
7d95e35:--stagedon line 23 belongs togitleaks, not torootline. Nothing in the repository invokes the flag:The
--stagedflag itself is real (rootline validate --helplists--staged validate only files in git staging area) — what does not exist is the hook wiring README describes. The sibling bulletREADME.md:374is accurate:.github/workflows/ci.yml:38really does run./rootline validate --all docs/roadmap/.2.
README.md:375— no merge-conflict analysis exists on any graph surfaceREADME.md:375claims:The whole
graphsurface:No such capability exists in the tree, and none ever did:
README.md:375is the only occurrence of the phrase in the repository — no code, no test, no other doc page.The nearest real thing is unrelated on both halves of the claim:
internal/rules/resolver.go:180ResolveLayered(path, root, monotonic)populates aConflictsslice, but it compares one.stemlayer against another.stemlayer — never.stemagainst document mutations — and its only CLI reach is themonotonic-violationsstem-health check insidevalidate --all(internal/rules/stemhealth.go:389). It is not the graph analyzer and it is not merge-conflict detection.3.
README.md:393— the required threshold is strictly greater than 80%README.md:392-393claims:Fixture
Built from scratch in an empty scratch directory. A version 2
.stem— a stem carrying onlyroot: trueis version 0 and is rejected before inference or validation ever runs, so it would prove nothing:.stemFive records.
owneris present in exactly four of them, which is exactly 80%. One record (control.md) deliberately omits the requiredtituloso the run carries a control error:Proof the fixture reaches real validation rather than stem-version rejection — the control error fired with the
.stemas itssource, and bothstem_healthandnoticesare empty:Run
initagrees — at exactly 80%owneris emitted with norequired: true:Positive control — add one more record carrying
owner, taking presence to 5/6 (83%), and the inference fires:The engine's own message says
>80%. The source agrees and always has:4eccab8is the commit that wrote≥80%into README; at that same commit the comparison was already>. The comparison has never been>=on any commit.Worth noting that the exact-80% case is not silent —
validation_gapsreportsrequired_understatementthere, gated at>= 0.80(internal/infer/validation_gaps.go:11). The two detectors are complementary by design; it is only README that names the wrong operator for the one that infersrequired.Expected Behavior
README.mddescribes what the shipped engine and the shipped hooks do, so that a reader who acts on it is not chasing a hook, a subcommand, or a threshold boundary that does not exist.Actual Behavior
README.md:373describes a.githooks/pre-commitstep that does not exist; the stringvalidate --stagedappears nowhere in the repository.README.md:375describes a graph capability with no code, no test, no flag and no other mention anywhere in the tree, on any commit.README.md:393states≥80%where the engine, its own inference message, anddocs/analyze.md:51,107all say>80%; at exactly 80% nothing is inferred.Environment
rootline version 9.12.1(equal toorigin/masterat7d95e35)Related work
all/every/most commandsoutput universals. Same file, different claims; both are documentation drift and neither blocks the other.docs/fix.md's deadinfer_from_childrenrow.README.md:351repeats that claim ("Proposals include ... infer fields from child documents") and is filed as a comment there rather than here, because it is the same dead detector (internal/proposal/proposal.go:484returnsnil, neutered inc31224e) rather than the same README section.docs/analyze.mdoverstatements. That page is correct on the>80%threshold, which is what makesREADME.md:393the outlier rather than a shared error.Labels owed by a maintainer:
documentation.