Drift & enforcement
For org admins.
Beyond checking docs against your standard (see Standards & conformance), Hekkos tracks drift — when the code and the docs disagree — and gives you the levers to act on it. This guide covers drift findings and their severity model, how drift surfaces on open PRs, the optional merge gate, documentation-authority tiers, the standing drift PR, and the Drift tab on the Sources page.
Three lenses: drift, principle, advisory
Hekkos surfaces three kinds of finding, unified as violations on the
Violations tab of Home (there’s no standalone Violations page — the old
/violations bookmark redirects into that tab). Each answers a different
question:
| Lens | Question | Example |
|---|---|---|
| Drift | Does the code match what’s documented? | a route the docs describe no longer exists |
| Principle | Does the code obey your declared rules? | an /orgs/{id} route is missing its tenant-auth middleware |
| Advisory | Is the code good practice, even when the docs agree? | the code uses AES-128 — and so do the docs, but it’s legacy |
Category. Every violation carries a subject category — security,
tenancy, architecture, dependencies, … — inherited from the rule it
belongs to. That’s what lets you ask “is password encryption respected
throughout the app?” and filter to the security category.
Principles are rules you author (Standards → Principles): a scope (which code they apply to) plus a condition, with a polarity — required (the code must satisfy it) or discouraged (flag any code that matches). Curated best-practice principles (weak crypto, deprecated dependencies) ship enabled and advisory by default:
Where a rule comes from. A principle is authored one of three ways: turned on from the catalogue (a curated preset), hand-written in the CEL editor, or extracted from a standards doc. Extraction reads a source you opt in as a standards source (a repo’s docs or a Confluence space), turns each normative statement (“must use…”, “do not use…”) into an advisory rule — binding a catalogue preset where one fits, else a generated check — and links it back to the document. An extracted rule carries a Source chip on its card; like every rule it starts advisory, and only becomes enforcing if you flip its Blocking toggle. A statement that maps to no precise check is skipped (not silently turned into a vague rule). Extraction, the standards documents behind it, and the Org → Initiative → Repo scope tree all live on the dedicated Policies page.
AI-judged rules (advisory). Some rules can’t reduce to a precise check — “error messages must not leak internals”, “services own their persistence”. For those, an admin can opt the org into the judged lane (Standards → Principles, off by default): during a scan, an AI judges the org’s semantic principles against the code and raises advisory findings. Every verdict is grounded (a finding citing code not shown to the model is discarded) and the lane never blocks a merge — only a deterministic rule can. Turning it on sends code context to the model; self-hosted deployments route it to a local model.
Scope: org, initiative, or project. A rule applies org-wide by default. Group
repos into an initiative (a department’s platform, say) and scope a rule to it in
the editor’s Applies to selector — it then applies only to that group. A repo is
judged against the union of its org-wide rules plus every initiative it belongs
to; deleting an initiative reverts its rules to org-wide.
they comment, never block, and you can disable any of
them or ignore an individual finding as not-applicable (it won’t come back
until the code changes). When you want one enforced, flip its Blocking toggle —
a deterministic principle can then gate merges through the
hekkos/principles gate (fuzzy rules stay advisory).
Principle and advisory findings are kept out of the Trust/Accuracy score and the
drift posture — those remain a pure code-vs-docs measure.
On the Violations tab, each finding’s code location is a deep-link to the
offending line on the default branch, and a principle finding links its rule to the
matching card on the Principles page. A Blocking badge marks the findings that
can actually stop a merge (the hekkos/principles gate), distinct from severity.
When a code area concentrates the violations — at least 40% of at least 10 — a
one-line nudge names that folder so you can clear the most at once; it’s read-only
(the fix is the code, so there’s no ignore-folder action here, unlike the Drift tab).
Real-state drift — when the code and the docs disagree
Beyond section conformance, Hekkos tracks whether your docs match the actual code. It extracts the real state (routes, env vars, functions, types, CLI flags) and diffs it against what the docs claim, producing drift findings with a severity model:
- critical — a doc points users at a route / env var / flag that no longer exists (they’ll hit failures).
- warning — a documented symbol is gone, or a documented signature no longer matches the code.
- info — real state that nothing documents.
The drift count is actionable drift only. The Drift severity on Home → Repositories, the repo’s Drift tab, and the drift posture on Insights all count findings where the docs disagree with the code (critical + warning). The info class — code nothing documents — is a coverage signal, not drift: it’s reflected in your doc-coverage score, not in the drift number. (Otherwise every undocumented internal helper would read as “critical drift,” which is what used to make the count balloon into the thousands.)
Wrapper-read env vars and flags aren’t false positives
An env var or flag your code reads through a config-loader wrapper — e.g.
get("DATABASE_URL") rather than a literal os.Getenv("DATABASE_URL") — used to
get flagged as a critical “documented but no longer in the code” finding,
even though the variable is very much still in use. It no longer does. Hekkos now
treats the bare name appearing anywhere in the code text as evidence the code
still uses it, so a documented-but-wrapper-read variable is quietly matched
instead of reported. Build-time env vars read the Vite/Astro/SvelteKit way —
import.meta.env.PUBLIC_APP_URL — are recognized as a direct read too, alongside
process.env.X and os.getenv, so a documented var read only through
import.meta.env is matched, not flagged. Only a documented env var or flag whose
name appears nowhere in the code stays a loud critical — that’s the
genuinely-removed case you actually want to hear about.
What no longer counts as drift
A drift finding is only useful if it names something real. Hekkos now discards a range of look-alikes before they can raise a finding, so the loud slots go to genuine mismatches:
- Placeholders. Backticked stand-ins in a template or example —
REPLACE_ME,CHANGE_ME,YOUR_TOKEN,EXAMPLE_KEY,TODO, and the like — are never treated as env-var contracts. - Ordinary words and SQL. Common prose verbs (
get,set,run,use) and SQL keywords (EXISTS,COUNT,IN,ON,DISTINCT, …) quoted in a doc are no longer mistaken for function or symbol names that “went missing”. - Filenames. A token that is shaped like a file (
budget_rescan.go) is no longer read as a code symbol that vanished. - Library calls. A symbol that belongs to a dependency you import
(
chi.URLParam) is matched against that dependency, not flagged as a missing symbol of your own. - Platform config. An
UPPER_SNAKEname mentioned right beside GitHub-platform wording — a repository secret, an Actions variable, an environment secret — is recognized as CI/platform configuration, not an application env var your code must still read.
Env vars in workflows and ops files count as evidence
An env var doesn’t have to appear in your application code to count as “still
used”. Hekkos now reads your ops surface as corroborating evidence — GitHub
Actions workflow YAML, shell scripts, Dockerfiles, Makefiles, .env files, and
Terraform / OpenTofu (.tf, .tf.json, and .tofu). A variable a doc mentions
that lives only in .github/workflows/deploy.yml (say GCP_PROJECT_ID) is
matched there instead of being reported as “documented but gone”.
Infrastructure is checked for drift too: a doc that names a Terraform resource,
variable, output, or module address is matched against the actual .tf /
.tf.json / .tofu files. The address can be written the way you’d reference it
in HCL — bare (aws_s3_bucket.assets), module-qualified
(module.vpc.aws_subnet.private), or for a for_each/count instance
(aws_instance.web[0]) — and all resolve to the same resource, so a doc pointing
at a resource that was renamed or removed is caught however it’s addressed.
The unverified tier
Not every doc reference can be checked with confidence. A bare, unfalsifiable anchor — a plain lowercase word a doc happens to backtick, with nothing in the code to confirm or deny it — used to be able to render as a loud “Critical”. It no longer can. Hekkos sorts findings into two tiers:
- Verified findings are the ones it can stand behind. These lead the PR, count in the headline, can be acknowledged, and can block (where blocking is enabled).
- Unverified findings are low-confidence guesses. They are collapsed into a single closed “Unverified” section, excluded from every headline count, never written into your docs, never given an acknowledge handle, and they never block a merge — because Hekkos genuinely can’t tell whether they’re drift. They’re shown only so nothing is hidden from you.
If a later extractor improvement lets Hekkos confirm one of these, it graduates into the verified tier on the next scan and starts counting normally.
On an open PR
When a pull request introduces new drift (its code change leaves a doc stale), Hekkos posts one comment summarizing what drifted. Findings are grouped by the doc file each stale claim lives in — the unit you’d actually open to fix them — under an honest headline count (e.g. 4 doc claims out of date · across 2 docs), not sorted into a wall of severity buckets.
- The comment is self-updating: it is edited in place on every push (never restacked into a wall of duplicate reviews) and is deleted once the drift is resolved.
- Each doc’s findings collapse into an expandable group, worst-affected doc first. When a single push turns up more than a screenful, the surplus is folded into one “+N more claims across M more docs” line that points at the repo’s Drift tab — so the comment stays skimmable no matter how much drifted.
- Lower-confidence guesses never lead: they are held in a separate collapsed Unverified section and left out of the headline count (see The unverified tier below).
- By default this is comment-only — Hekkos never blocks your merge.
- An org can opt into blocking (
pr_open_blocking_enabledin the drift config), in which case a canonical-tier finding at or abovepr_open_block_severityrequests changes (reference/spec sources never block — see authority below).
A suggested doc fix, written for you
Separately from the drift summary, when a PR’s code change leaves an existing doc stale, Hekkos may post a second comment — “Documentation Drift Detected” — containing the doc update it recommends, drafted from your diff. This is the same suggestion engine behind suggestion PRs, applied to the change you’re already making so the doc fix can ride along in review.
- Trivial PRs never get one. Doc-only, test-only, and dependency-bump changes are filtered out before any analysis, as are diffs with no visible doc impact — most PRs see no comment at all.
- One comment, refreshed in place. On each push Hekkos edits that same comment with its latest draft rather than stacking a new one, so the PR carries exactly one suggestion comment and it always reflects the current diff.
- Dismiss it the same way as any suggestion, by commenting on the PR:
/hekkos dismiss <reason>. If the merge gate (below) is enabled, dismissal also clears thehekkos/doc-driftstatus so the PR can merge.
When the stale line is in your diff, Accept is one click. If the doc claim that went stale sits on a line your PR actually edited, Hekkos posts a native GitHub suggested change on that line — Accept is the Commit suggestion button, no command to type. This only works for the minority case where the stale line is in the PR’s diff; the common case (the stale doc is elsewhere) is handled off-diff by the standing drift PR’s committed fix (below) and the dashboard, not an inline suggestion. A suggestion is only offered for a high-confidence fix with a single, unambiguous locus — Hekkos never rewrites a line it can’t pinpoint.
The merge gate (optional)
If a repo’s .hekkos.yml (see
per-repo overrides) sets
enforcement.merge_gate: true, Hekkos posts a hekkos/doc-drift commit status
on PRs that introduce documentation drift. Combined with a GitHub
branch-protection rule requiring that check, this blocks a merge until the
drift is addressed or the suggestion is dismissed.
The doc-standards merge gate
Separately from the drift gate above, you can make a doc type block merges
when it’s set to Blocking on the Standards
page. This is the enforcement side of conformance, and it posts its own
status context, hekkos/doc-standards — independent of hekkos/doc-drift,
so the two gates never clear or block each other.
What it blocks, and when. On each PR open/update, for every doc type you set
to Blocking, Hekkos checks the doc at the PR’s head and fails the
hekkos/doc-standards check only when a required doc or section is missing
(Missing / Sections missing). It is deliberately narrow and safe:
- Change-scoped — it only evaluates a Blocking doc type whose file the PR actually touches, so an unrelated PR is never blocked, and an external contributor’s PR can’t fan the check out across every doc type.
- Fails open — an off-standard/stale doc, a doc type with no authored standard, an unresolved path, a fresh repo not yet scanned, or any transient read error all pass. Editing a standard never retroactively blocks in-flight PRs.
- Org policy wins — a repo’s
.hekkos.ymlmay tighten enforcement but can never relax an org Blocking doc type.
Because it computes at the PR head, pushing an empty commit or reopening the PR can’t clear a genuine gap — only adding the missing documentation (or waiving the doc type) does.
Turn it on for a repo. Add hekkos/doc-standards to the repo’s required
status checks in branch protection — but, as with the drift gate, only after
you’ve set at least one doc type to Blocking and seen Hekkos post the check once.
Dismissing the gate
The hekkos/doc-standards check is a real merge blocker, so clearing it is
authorized. Comment:
/hekkos dismiss standards <reason>Only a commenter with write/admin access to the repo (or a Hekkos org admin)
can clear it — a read/triage collaborator’s dismiss is refused. The standards
token routes the dismiss to this context only; a plain /hekkos dismiss <reason>
(or /hekkos dismiss drift …) clears the softer drift nudge and never the
standards gate.
The policy conformance gate
The Principle lens (Standards → Principles) checks whether your code obeys a
declared rule — “all database access goes through the service layer”, “no weak or
outdated encryption”, “routes under /orgs/{id} are tenant-guarded”. Every principle
finding is advisory by default: it shows on the PR and the Violations tab, but
does not block. When you want one enforced, flip its Blocking toggle, and it
gates merges through a third, independent status context — hekkos/principles
(named for the Principles page, since it checks code, not documents; separate from
hekkos/doc-drift and hekkos/doc-standards).
What it blocks, and when. On each PR open/update, Hekkos evaluates your enabled
principles at the PR’s head and fails hekkos/principles only when the PR
introduces a violation of a rule you set to Blocking. It is deliberately narrow
and safe — the same posture as the other two gates:
- Introduced-only — a violation already present on the base branch is never gated (you can’t be blocked by pre-existing debt, and touching that file doesn’t trap the PR); only a newly-introduced violation blocks.
- Deterministic-only — only a rule Hekkos can prove (a value or graph check — Go AST, the import graph) may be set Blocking. Fuzzy/LLM-judged rules stay advisory forever, and a low-confidence (e.g. regex-tier) detection lands in the unverified tail and never gates.
- Fails open — no enabled blocking rules, no facts, an unsupported language, a fresh repo, or any transient scan error all pass. A scan error can never self-inflict a merge block.
The blocked PR’s Hekkos comment carries a Policy conformance section naming each introduced violation, its severity, and a link to the offending line.
Turn it on for a repo. Set at least one principle to Blocking on the
Principles page, let Hekkos post the check once, then add hekkos/principles to the
repo’s required status checks. As with the other gates, fork PRs are not gated
(Hekkos posts the repo’s own statuses), so scope the required check to repos whose
PRs come from branches.
The three gates, side by side
| Context | Checks | Blocks when |
|---|---|---|
hekkos/doc-drift | docs vs. code (drift) | a documented route/env/symbol no longer exists (org opt-in) |
hekkos/doc-standards | document structure | a required doc or section is missing (per-doc-type Blocking) |
hekkos/principles | code vs. a declared rule | a PR introduces a violation of a Blocking principle |
Documentation authority — stop old plans reading as drift
Hekkos tracks documentation wherever your repo keeps it — the root README,
the docs/ tree, a package-level site/README.md or web/README.md, .github/
notes — not just the root and docs/. (Anything under vendor/, node_modules/,
dist/, build/, or testdata/ is excluded.) That means a real contract in a
package README — say a marketing site’s env-var table — is checked for drift like
any other doc, but it also means internal notes and review reports now fall in
scope.
Not every Markdown file is a current-state contract. A repo often keeps historical
plans, specs, and design notes (e.g. under docs/), and by default a route or env
var mentioned in a superseded plan — or in an internal scratch note now in scope
— would be flagged as drift because the code moved on. Source-tier
authority fixes that without deleting anything: tier
those paths historical or ignored and they stop raising drift.
Under Settings → Documentation Authority, an admin adds ordered
(path glob → tier) rules that apply org-wide — to every repo — first match
wins, and anything unmatched stays canonical, so the feature is fully
automatic until you tune it:
| Tier | On a code–doc mismatch | Counts as coverage | In chat answers | Ingested |
|---|---|---|---|---|
| canonical | Loud drift findings — can block, where blocking is enabled | Yes — the document of record | Yes | Yes |
| reference | Warnings only — never blocks | Yes | Yes | Yes |
| historical | Raises no drift | No | No — excluded, so a cut feature in an old plan won’t resurface in chat | Yes — kept for lineage |
| ignored | Raises no drift — never checked | No | No | No — not ingested, never fetched |
For example, docs/rfcs/** → historical quiets an entire back-catalogue of
implemented RFCs in one rule. A dry-run button previews the effect against a
repo (“N findings, was M”) before you save. Rules live in the org’s drift config
(authority_rules) and take effect immediately — no re-scan needed.
This table governs org-wide rules only. To quiet a folder on a single repo
rather than everywhere, open that repo on the Sources page and switch to the
Drift tab — the concentration banner and
/hekkos ignore both write a repo-scoped ignore (below), which does not
appear in this table. Documentation Authority shows a read-only count of any
repo-scoped ignores and points you to the Drift tab to manage them; the editable
list here is org-wide rules only.
Planning trees are historical by default. Documents under plans/,
proposals/, or rfcs/ — at any depth, whether a repo-root plans/ or a
nested docs/plans/ — describe intended state, so a mismatch there is expected
rather than drift, and Hekkos tiers those trees historical automatically, with
no rule needed. (A leading **/ in one of your own authority globs matches the
same way: **/plans/** → historical covers both the root and nested plans/
trees, while still respecting segment boundaries — it won’t catch a myplans/.) Your own rules always win (first match), so if a plans/ folder is
actually a current-state contract for you, add an explicit … → canonical rule to
override. specs/, design/, and adr/ are not defaulted — a spec or ADR can
be a live contract, and API specs are matched against code as structured route
sources regardless.
Route paths reconcile across mount prefixes automatically: a doc’s full
orgs-scoped path (the .../widgets route under /api/v1/orgs/{id}) matches the
code’s handler-local registration for /widgets (any framework’s prefixing), so
you won’t see a route flagged as both “documented but missing” and “in code but
undocumented” just because of an API prefix. (These illustrative paths deliberately
omit the HTTP method: the extractor only treats a METHOD /path pair as a route
claim, so a guide explaining route matching never accidentally flags its own
examples.)
What the detector does NOT flag
The extractor is built to read contracts, not incidental text, so several kinds of mention never become drift:
- Fenced examples. A route in a diagram fence (
```mermaid) or afuncsignature in a non-Go fence is illustrative, not a contract — only prose, inline code, untagged fences, and route/Go-bearing fences (```http,```bash,```go) are read as claims. - Removed / planned mentions. A symbol on the same line as an unambiguous removal phrase (“was removed”, “no longer exists”), under a Known Stubs / Planned / Roadmap heading, or under a changelog Removed / Deprecated section (Keep-a-Changelog style), is demoted to the PR’s unverified tail rather than raised as a confident finding. A Changed section is not demoted — a modified-but-live contract still drifts loudly.
- Example & snippet docs. A code reference in a doc under an
examples/orsnippets/path is illustrative usage, not a live contract, so it is demoted to the unverified tail. Only the doc anchors are demoted — example source code is still inventoried, so a sample never becomes a false “undocumented”. - Non-code idioms that share a shape. CSS custom properties (a double-dash design token), CSS or crypto call forms (rgba(…), HKDF(…)), and GitHub webhook events written as a dotted provider.event pair are recognised as collisions and dropped or demoted. (These examples are written without code formatting on purpose — spelled as literal backticked tokens, they would be extracted as the very claims this section says are ignored.)
- Its own notes. The
<!-- hekkos-drift -->note Hekkos injects (below) is stripped before the next scan re-reads the doc, so a note never re-generates the finding it describes.
The standing hekkos/drift PR
Hekkos maintains one standing pull request per repo, on the hekkos/drift
branch, that collects the current drift and annotates the affected doc sections
with a note. For a changed signature the note shows the current signature
(“signature changed to …”); for a removed route/symbol/flag there is no current
value to show, so the note states plainly that the reference no longer exists in the
code. Its title says what and how many (e.g. docs: 12 doc claims out of date (4
docs)), and its body groups the findings by doc, leads with a short executive
summary, separates confident findings from an unverified (lower-confidence)
tail, and — when the drift clusters in one folder — nudges you toward the fastest
cleanup. Each finding line carries a deep link (↗) to the exact doc line the stale
claim sits on, and a signature-change finding also links the code location it now
disagrees with, so you can jump straight to what to fix. It is human-safe: if
you push your own commits to that branch, Hekkos will not overwrite them — it
comments instead.
When the PR first appears
The first drift PR for a repo is introduced gently, so a fresh install doesn’t open with a repo-wide rewrite:
- It follows your rollout pace. If your org is on the default pilot-first
rollout (see Rollout pace),
the very first drift PR for a repo is held back until that repo’s baseline scan
is a couple of days old, mirroring how suggestion PRs are paced. It opens
automatically once that window passes — you don’t have to do anything, and
/hekkos regeneratebypasses the wait if you want it now. - Volume is capped on first contact. When a repo turns up a large backlog of drift, the first PR writes in-doc notes for only the handful of most-affected docs and tells you how to author the rest — the body still lists the full count, but the diff stays reviewable.
- Concentration is surfaced, not annotated. If most of the drift is concentrated in one folder, the first PR annotates docs outside that folder and points you at ignoring the concentrated folder first (below) — rather than writing notes into the very folder it’s suggesting you quiet.
A real fix, committed for you
For the deterministic slice of drift — a documented signature that no longer matches the code, where Hekkos knows the exact correct value and can find the stale text unambiguously — the standing PR doesn’t just leave a note asking you to fix it. It rewrites the stale text to the correct value right in the PR’s diff, so Accept is merging the PR. The committed change replaces the note it would otherwise have written; you review a concrete one-line fix, not a “please update this” reminder.
This is held to a strictly higher bar than a note: it only fires on a high-confidence finding with a concrete replacement value and a single, unambiguous occurrence of the stale text. Anything Hekkos can’t rewrite safely — a deletion or rename with no replacement value, a claim buried in prose, an ambiguous match — stays a note for you to resolve by hand or acknowledge. Everything else that can’t be committed in-diff on your PR (the off-diff majority) lands here, on the standing PR, rather than as an inline suggestion.
One interaction model — Accept, Dismiss, Ignore
Everything Hekkos surfaces — a drift finding, a doc suggestion, a principle or advisory — takes the same three verbs, and each is recorded once (on a shared outcome log) so Hekkos learns what you accept. The verbs mean the same thing on every surface: the PR conversation, the standing drift PR, the Drift tab, the Violations tab, and the Suggestions panel on Home.
- Accept — “yes, keep/do this.” For a drift finding:
/hekkos ack(below), the Acknowledge button on the Drift tab, or a checkbox on the standing PR (see below). For a doc-fix suggestion: merge it — and for the deterministic slice Hekkos has already written the fix into the diff for you (see A real fix, committed for you below), so Accept is a one-click merge. - Dismiss — “no, this is wrong,” with a reason:
/hekkos dismiss <reason>on a suggestion comment, or Dismiss on the Suggestions panel. (A bare/hekkos dismissnow replies with usage instead of doing nothing — a reason is required so the dismissal is auditable.) - Ignore — “not here”:
/hekkos ignore <folder-glob>(admin), the Drift tab’s folder ignore, the per-finding “not applicable” on the Violations surface, or Ignore on the Suggestions panel.
Snooze — “not now.” A drift finding can also be snoozed for a set number of days (default 7): it drops off the active surfaces exactly like an Accept, but Hekkos automatically re-surfaces it when the timer expires if the drift is still real. It’s the honest middle ground between accepting a finding you haven’t decided on and ignoring one you don’t want to forget.
On the dashboard. The Suggestions panel on Home carries the same Accept / Dismiss / Ignore buttons for queued doc suggestions, so you can triage from the dashboard without opening each PR. Every one of these is written to the same outcome log as the PR-side verbs.
One-click checkbox accept. The standing drift PR renders a checkbox next to each note-residue finding — tick it to accept that finding, no command to type. Only org members can accept this way (Hekkos authorizes the person who ticked it).
Driving it from the PR conversation
/hekkos regenerate— rebuild the PR from the current real state (this does override your edits, since you asked). Org members only./hekkos ack <handle>— accept a specific drift finding so it stops surfacing until the underlying code changes again. Each finding line prints a short 12-character handle (not a long UUID) that you copy straight into the command./hekkos accept <handle>is an accepted synonym. Org members only./hekkos ack <doc-path>— bulk-accept every verified finding in one doc at once (e.g./hekkos ack docs/config.mdor/hekkos ack README.md), instead of acking them one line at a time. Only the verified findings are acked; any unverified guesses in that doc are left untouched (they never blocked or counted anyway), and Hekkos tells you how many of each it handled. Org members only./hekkos ignore <folder-glob>— tier a whole doc folderhistoricalso it stops raising drift, straight from the PR (e.g./hekkos ignore docs/rfcs/**). The ignore is scoped to this repo only — the one the PR lives in — so other repos in your org are unaffected, even if they have a folder at the same path. Org admins only — a non-admin who tries it is refused with a reply. On success Hekkos appends the rule, quiets that repo’s matching findings, and replies with exactly what it ignored, the fact that those docs also drop out of Hekkos chat answers for this repo (see the RAG trade-off below), and how to undo it — on this repo’s Drift tab → Ignored folders (open the repo on the Sources page). This is the same repo-scoped ignore as the Drift tab’s concentration banner, driven from GitHub.
Old full-UUID /hekkos ack commands from previously-opened PRs keep working, so
nothing you’ve bookmarked breaks. (/hekkos dismiss is not a drift command —
it belongs on suggestion comments; used here, Hekkos replies pointing you to
ack/accept instead.)
Acting on a finding refreshes the PR
/hekkos ack and /hekkos ignore now rebuild the standing PR in the same
job. Accept or ignore a finding and the PR’s body, title, and count update to
match immediately — no more acking a finding and watching it linger in a PR that
never changed. (An ignore that clears hundreds of findings updates the PR in
one pass.) The human-safe guard still holds: if you own the branch, Hekkos
refreshes nothing and comments instead.
When everything clears
Once the last finding behind the PR is resolved, acknowledged, or ignored, Hekkos closes the loop instead of leaving a stale PR open forever:
- If your docs still carry drift notes from a previously merged rebuild, Hekkos flips the PR to a note-removal PR (retitled docs: remove N stale drift notes — all clear) and leaves it open — merging it strips those now-orphaned notes out of your docs.
- If there’s nothing left to clean up, Hekkos closes the PR with an all-clear comment. If drift regresses later, a fresh PR opens.
- Notes that were merged into your default branch and later acknowledged or ignored are treated as orphaned and removed on the next rebuild, so a merged note never outlives the finding it described.
Hekkos won’t heckle its own PRs
The drift check is skipped on Hekkos’ own branches (hekkos/drift and
hekkos/doc-improvements). Refreshing the standing PR — even a force-push — will
never make Hekkos post a drift comment on its own pull request. (The guard is an
exact branch-name match on Hekkos-pushed branches in your own repo, so naming a
branch hekkos/… yourself, or opening one from a fork, doesn’t dodge analysis.)
The Drift tab
The Drift tab on the Sources page (open a repo from the list and switch to the Drift tab, visible to every member) is where a repo’s drift lives — it renders whether or not you’ve adopted a doc standard.
Open Documentation Drift is deliberately distinct from Real-State Trust: it’s a count of doc/code mismatches, not a Trust score, so a big raw number here does not by itself drag your Trust down.
Pick a repo from the list and its Drift tab shows its findings worst-first, each with its effective
severity and its source (built-in default, an org severity rule, or a per-finding
override), the code file:line, and the doc location — with acknowledge and
override-severity controls on every finding. Acknowledging a finding stops it
surfacing until the underlying code changes again. The list shows honest empty,
error, loading, and not-yet-scanned states — an error is never dressed up as
“no drift”.
The repo’s detail header also carries a live Real-State Trust badge — a small SVG scored the same way as the org-wide Trust number and banded green / amber / red. By default it’s authenticated and in-app: it renders for a signed-in member viewing the repo, and the same URL returns nothing to anyone without a session.
Sharing the badge in a public README. If you want the badge on a public
README, an admin can flip Public badge to on in the repo’s detail
header. This is off by default and opt-in per repo — Hekkos never exposes a
repo publicly on your behalf. Once on, the header shows a copy-ready markdown
snippet () that loads from an
unauthenticated URL, so it works in an open repo. That public badge exposes
only the numeric Trust percent and its band color — never file paths, doc
or finding text, entity content, or even the fact that the repo exists: a repo
that isn’t published (or any unknown id) returns an identical neutral
docs trust: private badge, so the public URL can’t be used to probe your private
repos. Flip it back to off at any time and the public URL immediately reverts
to that neutral badge.
Priority to document
Above a repo’s findings, a Priority to document panel ranks its
undocumented code by call-graph centrality — how many other entities and
routes depend on each one — so you document the highest-impact gaps first instead
of triaging a flat list. Each row names the entity and its file:line, how many
callers point at it, and a route badge when an HTTP route targets it
directly. A clean or not-yet-scanned repo shows a short teaching empty state
rather than looking broken.
The same call graph is exposed to agents as two MCP tools — risk_ranking
(this ranking) and impact_of (the blast radius of a single entity) — so you
can ask the same questions from your IDE (see
Ask Hekkos & MCP).
The concentration banner — ignore a whole folder at once
When a single doc folder dominates a repo’s findings (the classic case: hundreds
of stale references all coming from docs/rfcs/** or an internal planning
directory), the Drift tab shows a concentration banner naming that folder.
An admin gets a one-click Ignore this folder button; a member sees the nudge
but is told to ask an admin.
Ignoring the folder tiers it historical as a repo-scoped ignore — scoped to
the selected repo, not org-wide — so it stops raising drift on this repo while
leaving every other repo untouched. It is the same repo-scoped action as
/hekkos ignore typed on that repo’s PR. Before anything is saved you get a
dry-run preview of the exact effect on that repo (“this repo would show N →
M drift findings”) and a plainly-stated trade-off you must confirm:
Ignored folders (per repo)
Once a repo has at least one repo-scoped ignore — created by the concentration
banner above or by /hekkos ignore on one of its PRs — the Drift tab lists them
under Ignored folders for the selected repo, each with an Un-ignore
control (admins only). This is the single place to review and undo a repo’s
ignores; they deliberately do not appear in Settings → Documentation
Authority, which is org-wide rules only. The list shows only the selected repo’s
ignores, so switching repos in the picker changes what you see.
Un-ignoring a folder removes the rule, but its findings don’t reappear instantly — they return on the next scan of that repo. The row disappears right away, so don’t read the still-quiet findings as “un-ignore didn’t work”; they’ll come back once Hekkos next scans the repo.
Tuning severity defaults
Under Settings → Drift Severity Rules, an admin can override the built-in
default severity for a drift kind — the key is a drift kind (doc_only) or a
kind:entity_kind pair (doc_only:env_var). For example, set
doc_only:env_var to info if that class is noisy for your org. This sits
alongside the per-finding override on the Drift tab (which retunes a single
finding) and the source-tier authority rules (which quiet whole doc paths).