Changelog
All notable changes to coderef are recorded here.
The format follows Keep a Changelog;
versions follow SemVer.
Unreleased
v0.5.0 — 2026-06-18
Highlights
- Per-pattern
patterns.<id>.labelconfig +label.orphanOpen
/label.orphanClosedoctor diagnostics (#68) —kind: "ifchange"patterns can now declare a compat-form open/close
marker pair (e.g.BEGIN_BLOCK(id)/END_BLOCK) the parser
recognises alongside the canonicalIfChange/ThenChangeand
the globalLabel/EndLabel. Two new compat-only doctor
checks fire on stray open/close markers when at least one
pattern opts in. - References-browser
Driftedfilter (#69) — third filter
mode joinsall/mine. Surfaces ifchange refs whose
enclosing IfChange/Label region in the same file is unbalanced.
The full DESIGN §10.14 checksum-drift backend remains
post-v0.4 backlog; this ship exposes the parse-time orphan
signal via a TS-side single-pass scanner — no new wasm
exports, no CLI subprocess.
Workspace stats
- Extension TS test count grew 55 → 66 (Drifted filter: 14 new
tests forcomputeOrphanLines+isReferenceDrifted+ the
setFilterCommanddrifted-mode quick-pick). - Rust test count grew (34 → 38 doctor-pipeline integration
tests for the newlabel.orphanOpen/label.orphanClose
diagnostics; existingOrphanIfChange/OrphanThenChangetest
expectations updated for the split into four variants). - Two new
MarkerParseErrorvariants (OrphanLabel,
OrphanEndLabel) — pre-1.0 coderef-core API; only internal
consumers (coderef-cli,coderef-core-wasm) updated in this
release cycle. - 2 PRs merged in this cycle (#68 per-pattern label config /
orphans, #69 Drifted filter).
Deferred — no v0.5 backlog
v0.5 closes out the v0.4 deferral list. There's no enumerated
v0.6 backlog: DESIGN §20.5 explicitly leaves the post-v0.4
horizon open and waits for real-use signal before committing
further scope. Open candidates documented there (checksum-drift,
LSP server, JetBrains plugin, extends: mechanism, semantic
response filtering, CodeLens, …) are picked up case-by-case if
demand surfaces.
Added
- Per-pattern
patterns.<id>.labelconfig (DESIGN §10.3).
Eachkind: "ifchange"pattern can declare a compat-form
open/close marker pair (label.open.regexand
label.close.regex) that the parser recognises in addition
to the canonicalIfChange/ThenChangeand the global
Label/EndLabel. Useful for codebases mirroring
ebrevdo/ifttt-lintor other coupled-change tools with
different keyword spellings (e.g.BEGIN_BLOCK(id)/
END_BLOCK). Configurable per-pattern, but the marker
recognition is global at scan time — any pattern's configured
markers are tried against every file. label.orphanOpen/label.orphanClosedoctor diagnostics
(DESIGN §10.3). Compat-only — they fire ONLY when at least
one pattern haslabelconfigured. Catches stray compat-form
open markers (Label(...)or per-pattern open) with no
matching close, and vice versa. DefaultError. The
canonicalIfChange/ThenChangeorphans keep firing as
parse-error/orphan-ifchangeand
parse-error/orphan-thenchangevia the existing path.- Parser now tracks
MarkerForm::Canonicalvs
MarkerForm::Compaton everyIfChangeBlock(hidden field —
doctor-internal). Used by the new orphan diagnostics to pick
the right Orphan* variant. Two newMarkerParseError
variants (OrphanLabel,OrphanEndLabel) replace the
previous conflation withOrphanIfChange/
OrphanThenChangefor compat-form orphans. - References-browser
Driftedfilter (DESIGN §14.7.4). The
coderef.references.filtersetting / quick-pick gains a third
mode,drifted, alongsideallandmine. With it active,
the tree shows onlykind: "ifchange"references whose
enclosing IfChange/Label region in the same file is unbalanced
— an open marker with no matching close, or a stray close
with no open. Useful for "where are the ifchange markers that
the parser considers broken in this branch?". The full DESIGN
§10.14 checksum-drift backend remains post-v0.4 backlog; this
v0.5 surface exposes the parse-time orphan signal we already
have via a small TS-side single-pass scanner — no new wasm
exports, no CLI subprocess. 14 new unit tests in
extension/src/referencesView.test.ts.
v0.4.0 — 2026-06-18
Highlights
- References-browser Mine filter (#66) — workspace identity list
- per-ref substring match against matched text and capture
values; toggleable via the newcoderef.references.setFilter
palette command.
- per-ref substring match against matched text and capture
- Multi-target hover alternates (#65) — the HoverProvider lists
every other pattern that would also match the samematched_text
with the alternate's resolved target as a clickable link.
Workspace stats
- Extension TS test count grew from 45 → 55 (Mine: 7 new tests;
hover alternates: 3 new tests). - 2 PRs merged in this cycle (#65 multi-target hover, #66 Mine
filter).
Deferred to v0.5
- Per-pattern
patterns.<id>.labelconfig +label.orphanOpen
/label.orphanClosecompat-only doctor diagnostics (DESIGN
§10.3). Requires a parser refactor (build marker regex set from
pattern configs; track per-block marker provenance) plus a real
design call on per-pattern file scoping. - References-browser Drifted filter (DESIGN §14.7). Requires
either subprocess plumbing (coderef check --report jsonfrom
the extension — brings CLI-on-PATH dependency) or exposing the
verifier through WASM (no HTTP in WASM today). Both are
real-design items, not "ship the smallest cut" candidates.
Added
- References-browser Mine filter (DESIGN §14.7 v0.3 deferred /
v0.4). Newcoderef.references.filtersetting (all/mine,
defaultall) controls whether the tree shows every reference
or only those that match the user. Identity source is a workspace
arraycoderef.references.mineIdentities; a ref is "yours" if
its matched text or any capture value contains any listed
identifier (case-insensitive substring match). With an empty
mineIdentitiesarray, Mine acts as a no-op (treats every ref
as yours) rather than emptying the tree — fewer foot-guns. New
coderef.references.setFilterpalette command pops a quick-pick
and triggers an immediate rescan on selection. - Multi-target hover alternates in the VSCode extension's
HoverProvider(DESIGN §14.7). When hovering a reference the
popover now lists every other pattern that would also match the
samematched_text, with the alternate's resolved target as a
clickable link. Useful when one token is interpretable several
ways — e.g. a JIRA id matched both by ajirapattern (linking
to the tracker) and a generic ticket pattern (linking to a
dashboard). The primary target stays at the top of the popover
(driven by pattern priority via the cache); alternates appear
below in anAlternative targets (N):section. buildHoverMarkdown(the pure renderer) gained analternates
parameter — backward-compatible (defaults to[]), so callers
that don't pass it see the same v0.2 single-target hover.
v0.3.0 — 2026-06-15
Highlights
- IfChange/ThenChange v0.3 surface complete:
Label('name') ... EndLabelcompat-form markers (#54),{soft}glob flag (#55),
strict{all}glob semantics with workspace enumeration (#56),
three newlabel.*doctor diagnostics (#57). - New doctor diagnostics:
commitMessage.requiredNeverFires
(#58, withgit logcorpus plumbed from the CLI),
references.tooManyNodes+references.uncategorisedSpike
(#61). - References-browser polish: Copy-as-Markdown (#59),
exportJson (#60),coderef.references.maxNodesPerLevelcap
with truncation placeholder (#62),scanModesetting +
setScanModepalette command (#63).
Workspace stats
- Test count grew from ~352 → ~370 (Rust workspace) + 28 → 45
extension TS unit tests. - 6 PRs merged in this cycle (#54–#55, #56, #57, #58, #59, #60,
#61, #62, #63).
Deferred to v0.4
- Per-pattern
patterns.<id>.labelconfig +label.orphanOpen/
label.orphanClosecompat-only doctor diagnostics (DESIGN
§10.3). Needs a design decision on per-pattern file-scoping vs
workspace-wide opt-in before the parser refactor is justified. - References-browser Mine / Drifted filters (DESIGN §14.7). Mine
needs an identity source (git config vs config-listed
identifiers); Drifted needs verifier-output plumbing. - Multi-target hover alternates in the extension's HoverProvider.
Added
- References-browser scan modes + setScanMode command (DESIGN
§14.7). Newcoderef.references.scanModesetting controls which
files the references browser walks on refresh:workspace
(default — every in-scope file honouring .gitignore + config
ignore[]),openFiles(only currently-open TextDocuments), or
currentFile(only the active editor's file). New
coderef.references.setScanModepalette command pops a
quick-pick with descriptions per mode, persists the choice to
workspace (or user-global) settings, and triggers an immediate
rescan. Useful on very large repos where scanning everything is
the slow path. coderef.references.maxNodesPerLevelsetting + tree truncation
placeholder (DESIGN §14.7.3). The references browser now honours
a per-workspace cap (default1000, min10) on the number of
nodes shown at any level — per-category file list, per-file leaf
list. Levels exceeding the cap render the first N entries and an
ellipsis-icon…and X more (cap: N, set coderef.references.maxNodesPerLevel to raise)placeholder. Pairs
with thereferences.tooManyNodesdoctor diagnostic (also v0.3)
so very large levels are flagged ahead of viewing the tree.references.tooManyNodes+references.uncategorisedSpike
doctor diagnostics (DESIGN §14.7.3). Two new scan-dependent
Info-severity checks for the references-browser tree.
references.tooManyNodesfires when any pattern matches more
than 1000 references workspace-wide, or any single file contains
more than 1000 references — both signal that the references
browser will truncate the corresponding tree branch and a more
granular grouping is in order.references.uncategorisedSpike
fires when more than 10% of references land in theother
fallback category — suggests declaringcategoryexplicitly on
more patterns.- References-browser exportJson command (DESIGN §14.7 v0.3 long
tail). Newcoderef.references.exportJsoncommand pops a save
dialog and writes the current reference set to disk as a stable
schema-versioned JSON document. Schema1includes a header
(generated_at, engine version, totals) plus one entry per
reference with its resolved category baked in, so downstream
tooling can group/filter without re-reading the config. Entries
are sorted by(file, byte_start)so the output is diffable
across runs. Surfaced as a save-as-icon button in the
references-browser view title bar (between the Copy-as-Markdown
and Refresh icons). - References-browser Copy-as-Markdown command (DESIGN §14.7 v0.3
long tail). Newcoderef.references.copyAsMarkdowncommand shows
up as a clippy-icon button in the references-browser view title
bar. Click it (or run from the command palette) and the current
reference set lands in your clipboard as a category-grouped
Markdown document, suitable for pasting into a PR description, a
design doc, a ticket comment — anywhere the team is already
reading Markdown. Format: one section per category (display-order
sorted), each section subdivided per file, each file as a bullet
list ofpath:line—[pattern] matched-text→ target lines.
Backticks in matched text are escaped so the inline-code spans
don't break. commitMessage.requiredNeverFiresdoctor diagnostic (DESIGN
§16.1.1). A pattern declaredscope.commitMessage: "required"
whose regex doesn't match any commit in the host-supplied corpus
is flagged atWarningseverity.coderef doctornow walks
git log -n 200 --format=%B(NUL-separated bodies) and feeds the
result to a new
run_doctor_with_workspace_and_commit_corpus(root, cfg, msgs)
entry point incoderef-core. The original
run_doctor_with_workspace(root, cfg)stays as a 2-arg backward-
compatible alias that passesNonefor the corpus. With no
corpus (host couldn't reach git, not a repo, or the log is
genuinely empty), the check is silently skipped rather than
flagging every required pattern as never-fired.label.*doctor diagnostics (DESIGN §10.3). Three new
scan-dependent checks fire when at least onekind: "ifchange"
pattern is configured:label.duplicateInFile(Error — two labelled
regions in the same file share an id; resolution is
non-deterministic),label.unused(Info advisory — labelled region
with no peer block and noThenChange(path:label-name)reference),
andlabel.ambiguousName(Error — name is purely numeric or matches
N-M, colliding with line/range parsing inThenChange(path:line)
targets). The remaining DESIGN §10.3 diagnostics
(label.orphanOpen/Close) are explicitly compat-only and pair
with the per-patternpatterns.<id>.labelconfig in a follow-up
PR.- Strict
{all}glob semantics inThenChange(DESIGN §10.2).
IfChange ... ThenChange(/docs/*.md{all})now enforces that every
workspace file matching the glob is touched by the diff, not just
"at least one" as the v0.2-shipped lax semantics required. Powered
by a newenumerate_workspace_fileshelper incoderef-coreplus
a newworkspace_files: Option<&[String]>parameter on
verify_changes_composable. The CLI'scoderef changeswalks
the workspace with the same.gitignore+ configignore[]
semantics that block-scanning uses, so the file universe stays
consistent. Callers without a workspace handy (WASM in-editor
path, isolated unit tests) passNoneand{all}falls back to
the lax v0.2 any-mode behaviour. Empty match set is a vacuous
pass — a stale-glob doctor check is the right surface for that,
not a coupled-change violation. {soft}glob flag onThenChangeglob targets (DESIGN §10.2
severity modifier). AThenChange(/docs/*.md{soft})target whose
matched-and-changed count is zero still surfaces a violation, but
withSeverity::Warning—ChangesReport::passed()ignores
warnings, socoderef changesexits 0. The flag is comma-combinable
with the existing{any}/{all}mode flags:{soft,all}(and
{all,soft}) mean "every matched file should change, but if not,
warn rather than fail". The previous single-flag-only parser is
generalised to a comma-separated flag set inside the braces.GlobFlagenum split intoGlobMode { Any, All }(mutually
exclusive match-mode) andGlobFlags { mode, soft }(struct that
groups the mode with the orthogonalsoftseverity bit). All
Target::FileGlobsites now carryflags: GlobFlagsinstead of
flag: GlobFlag.format_targetomits the brace suffix entirely
when the flags are at their default (any-mode, not soft) so
violation messages don't sprout a redundant{any}on every
default glob.ViolationandViolationReportcarry aseverity: Severity
field. JSON consumers that ignore unknown fields keep working
(additive change); consumers that depend onseverityget
"warning"for soft glob misses and"error"for everything
else.- CLI
coderef changes --report textprefixes warning violations
with[warn/missing-target]instead of the plain
[missing-target]; the trailing summary line splitsviolation(s)
intoerror(s)andwarning(s)so the reader can see at a glance
whether the run failed because of a hard mismatch or only flagged
soft ones. split_targets(the comma-splitter for theThenChange(...)arg
list) now respects{...}brace boundaries — commas inside a
flag set don't split into separate targets.Label('name') ... EndLabelmarker recognition in the IfChange
block parser (DESIGN §10.2 / §10.3 compat form). The compat markers
are now parsed as alternative open/close pairs alongside the
canonicalIfChange / ThenChange— they produce the same internal
IfChangeBlockrepresentation with the captured id, so a
ThenChange(path:label-name)elsewhere can target either form's
labelled region. Cross-form pairing is allowed
(Label('foo') ... ThenChange(targets),IfChange('bar') ... EndLabel)
so codebases mid-migration aren't forced into one spelling. Per-pattern
config (DESIGN §10.3patterns.<id>.label) and the
label.*doctor diagnostics (orphanOpen, orphanClose, duplicateInFile,
unused, ambiguousName) remain v0.3+ work — this PR ships the parser
recognition only.
Changed
npm_publish.ymlworkflow now triggers on tag push instead of
the previously-usedrelease: types: [published]event. The former
shape never fired because GitHub Actions suppresses workflows
triggered by events caused by a workflow's ownGITHUB_TOKEN
(anti-recursion). The new shape adds a poll-and-wait step that
blocks up to 30 minutes forrelease.ymlto finish building and
creating the GitHub Release, then publishes. Effect for releasers:
pushingvX.Y.Znow fires all three channels (GitHub Release, npm,
VSCode Marketplace) zero-touch — no manualgh workflow runfor
npm anymore.
v0.2.2 — 2026-06-14
Fixed
- npm wrapper
install.jsno longer copies a script as if it were a
binary, fixing the infinite-recursion silent hang where the second
npm install -g @helly25/coderefafter a v0.2.1 install would copy
the npm shim left by the prior install (a#!/usr/bin/env node
script) intobin/coderef, so the wrapper spawned itself
recursively.install.jsnow sniffs the magic bytes of any candidate
before copying — accepts ELF, Mach-O single-arch, Mach-O Universal
(CA FE BA BE, whatlipoproduces and what/bin/lsis on macOS),
and PE; rejects anything beginning with#!.
v0.2.1 — 2026-06-14
Highlights
kind: "block"— source-levelDO NOT COMMIT/NOCOMMIT/
DONOTMERGEguards. The match itself is the diagnostic;coderef checkexits 1 on the first hit, blocking the pre-commit hook
(PR #26).- Pattern categories (DESIGN §5.7) —
files/people/tickets
/standards/urls/coupled-change/other+ user-defined.
Doctor surfacescategory.unset,category.tooBroadOther, and
scan-dependentcategory.mismatch.coderef patterns --by-category
groups in DESIGN-order display (PR #28, #41). - Markdown anchor verification (DESIGN §6.3) —
DOCREF(/path.md#section)
verifies the anchor against the target file's heading slugs.
Slugifiers:github(default),pandoc,gitlab,hugo,
mkdocs-material. Pandoc explicit{#id}overrides honoured under
every slugifier. Suggests Levenshtein-1 hits on miss (PR #29, #36). coderef commit-msglinter (DESIGN §16.1.1) — runs the pattern
engine over a commit-message file (or stdin), with per-pattern
scope.commitMessageopt-in /"required"enforcement (PR #30).coderef changesIfChange/ThenChange verifier (DESIGN §10) —
three-pass coupled-change algorithm with full Shape A / B / C
support. ThenChange targets: bare file,path:N/path:N-M,
path:label-name,path#anchor, glob (path/*.md{any|all}). Shape
C composable ids (IfChange(JIRA(PROJ-1234))) resolve through the
reference engine so blocks in different files coalesce. NoVerify
escape hatch + 11 integration tests (PRs #31, #37, #38, #39, #40).- References browser — activity-bar tree view in the VSCode
extension. Category-first grouping (DESIGN §5.7.3 display order),
click-to-jump, live updates via file-system watcher (PR #34). - Doctor diagnostics shipped —
category.unset,
category.tooBroadOther,category.mismatch,anchor.skippedExt,
anchor.styleMismatch,commitMessage.allDisabled,
commitMessage.ifchangeMisconfigured,coupled.composableTypo
(PR #28, #35, #41). - CI infrastructure — bzl-style
doneaggregator gate with a yq
self-check that fails CI if any newly-added job isn't wired into the
required-check list (PR #32, #33). Synced to mbo, bashtest, proto,
vscode-iwyu, mbo-tools.
Removed
- x86_64-apple-darwin (Intel Mac) release binary. Apple stopped
shipping Intel hardware in 2023 and GitHub'smacos-13runner queue
was the slowest in the release matrix (PR #43). The npm wrapper now
emits anunsupported platform/archerror fordarwin x64instead
of trying to download a missing asset. Apple Silicon Macs (the
aarch64-apple-darwinbinary) are unaffected.
Fixed
- UTF-16 ↔ UTF-8 offset translation in the VSCode extension's
hover and DocumentLink providers. Files containing em-dashes,
emoji, or CJK characters no longer shifted ref positions by N
multi-byte characters (PR #27).
Workspace stats
- Test count grew from 209 → 368 (Rust + integration).
- 7-job CI matrix (
rust/wasm/extension/npm-wrapper/
schema/docs/done); branch protection requires onlydone.
Deferred to v0.3
commitMessage.requiredNeverFiresdoctor check (needs git-log
corpus plumbing).- Strict
{all}glob semantics (needs workspace-wide enumeration). {soft}glob flag (warning severity).Label('name') ... EndLabelcompat form (per-pattern label config).- References-browser longer tail: scan modes, Mine/Drifted filters,
Copy-as-Markdown, exportJson. - Multi-target references, network profiles,
coderef upgrade
codemod, visual config editor, external-URL anchor verification.
v0.2.0 — yanked, never shipped
The original release run (workflow 27498341045) was cancelled while
the x86_64-apple-darwin build sat in the macos-13 GitHub Actions
queue. The matrix was reshaped to drop Intel Mac support (PR #43, #44)
and the actual release ships as v0.2.1. The v0.2.0 tag exists on
the remote as an orphan ref with no GitHub Release, no published
binaries, and no presence on npm or the VSCode Marketplace.
v0.1.0 — 2026-06-07
Minimum viable foundation:
- Pattern engine + JSONC config loader.
- HTTP verifier (HEAD + GET fallback, configurable timeout).
- VSCode extension with DocumentLinkProvider + HoverProvider,
in-process WASM-shared core so editor and CLI never diverge. - CLI subcommands:
config show,list,check,doctor,
patterns,explain,help. - Pre-commit hook plumbing.
- npm wrapper (
@helly25/coderef) that downloads platform binaries
from GitHub Releases on install. - Distribution: GitHub Releases (CLI binaries) → npm wrapper →
VSCode marketplace, ordered (docs/release.md).