Skip to content

Rename fastcached to Pace (0.6.0) - #1714

Merged
christianparpart merged 13 commits into
masterfrom
feature/pace-rename
Oct 18, 2026
Merged

christianparpart merged 13 commits into
masterfrom
feature/pace-rename

Conversation

@christianparpart

@christianparpart christianparpart commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

fastcached is renamed Pace for release 0.6.0. It is a coordinated clean break: nothing reads an old name. The design was agreed with @Yaraslaut.

The names

Before After
fastcached pace-kv
fastcache-compile-node pace-node
fastcache-cc pace-cc
fastcache-cli pacectl
FASTCACHE_* env, FASTCACHED_* CMake PACE_*
metrics fastcached_* / fastcache_* pace_* (285 series, no collisions)
src/FastCache/, namespace FastCache src/Pace/, namespace Pace
/etc/fastcached, %ProgramData%\fastcached /etc/pace, %ProgramData%\pace
state …/fastcache-node, …/fastcached …/pace-node, …/pace-kv
Windows services FastCached, FastCacheCompileNode pace-kv, pace-node
DNS SRV _fastcache._tcp _pace._tcp
repo LASTRADA-Software/fastcached LASTRADA-Software/pace (already renamed, so the rewritten issue links resolve)

Deliberately unchanged, each listed with its reason in scripts/brand-leftovers-exemptions.tsv:

  • the signing labels fastcache-*-vN, which are domain-separation constants (changing signed bytes needs version bumps);
  • FCOW, and the CoW store's marker keys "\0\1fastcached.fmt" / ".mig", which are on-disk format;
  • objkey-v8 and manifest-v9, so no cache is invalidated.

How to review it

The first commits are mechanical. Each message records:

  • its rule table;
  • the match count per rule, re-measured against the commit's parent;
  • every hand edit, by file.

Re-run a commit with the recorded tool and compare it, rather than reading 1,700 files.

What changed by hand:

  • docs/upgrading-to-pace.md: per-OS steps.

    • Every fleet member is re-enrolled: a node's identity does not survive the new service account.
    • Configs must be saved before the macOS uninstaller runs.
    • The renamed MSI properties, the fleet pin, and the X:\LASTRADA\Tools\pace\<version>\ distribution (the old …\fastcache\ directory stays for builds still pinned to fastcached).
  • Packaging. Pace is a new product with a new MSI upgrade code, and it refuses to install while fastcached is installed: an MSI launch condition, Conflicts: fastcached, and a macOS preinstall check.

    • CI installs the real 0.5.0 MSI and proves the refusal, then a clean install, the services, the seeded config, a Pace→Pace upgrade and the uninstall.
  • New per-user node units: pace-node-user.service, and the node's LaunchAgent (pace-node --install-service --service-scope=user).

  • Two refusals that name the old spelling and read nothing:

    • a FASTCACHE_* warning from pace-cc and pace-node;
    • a configure error on a stale FASTCACHED_* cache.

    Both are removed in 0.8.0 (Remove the FASTCACHE_*/FASTCACHED_* refusals added by the Pace rename (due 0.8.0) #1713).

  • brand-leftovers: no fastcache outside the exemption table, stale rows are refused, and its stated blind spot is names assembled character by character.

Verification

  • CI: green on the final head; the macOS notarization step was re-run after an Apple CloudKit network error.
  • Local gate under WSL: both legs.
  • Every commit with compiled changes builds on its own (cl-debug).
  • The MSI, also built locally with WiX 5.0.2: table checks for the launch condition, the old-product detection, both config templates, and the pace ProgramData directory.
  • A final whole-branch review, with every finding fixed.

Closes #1662

src/FastCache moves to src/Pace, every <FastCache/...> include becomes
<Pace/...>, namespace FastCache becomes namespace Pace, and the library
and test targets are Pace and PaceTest. Purely lexical: the only prior
"Pace" in the tree is a verb in a comment.

Generated, not hand-edited:

    python -I rename.py rules-cpp.tsv exemptions.tsv <worktree>

rules-cpp.tsv (rule, scope, regex, replacement, expected = measured):

    mv:src-FastCache	src/FastCache/*	^src/FastCache/	src/Pace/	579
    include-angle	*	<FastCache/	<Pace/	3249
    include-quote	*	"FastCache/	"Pace/	8
    src-path	*	src([/\\]+)FastCache\b	src\g<1>Pace	500
    test-target	*	\bFastCacheTest\b	PaceTest	92
    ninja-target	*	(?<=_)FastCache(?=_|Test_)	Pace	3
    lib-file	*	\blibFastCache\b	libPace	1
    token	*	\bFastCache\b	Pace	7083

exemptions.tsv protects the signing labels (fastcache-*-vN) and the
jitbit/FastCache project name, which is not ours. vendor/monocypher is
never read.

Signed-off-by: Christian Parpart <christian@parpart.family>
@christianparpart christianparpart added the type/chore Dependencies, CI plumbing, release mechanics, repo hygiene label Oct 18, 2026
@github-actions github-actions Bot added area/launcher apps/fastcache-cc/ - the compiler launcher and its cache key area/compile-cache CompileCache/, the 0xFC wire, the executor, PathCanon area/distributed Distributed/, apps/fastcache-compile-node/ - dispatch, workers, scheduler area/storage Cache/, CowTree/ - engine, LRU, layered, sharded, compression area/platform Platform/, Config/, Cli/ - service registration, config lookup, the CLI table area/packaging packaging/, CPack, deb/rpm/pkg/msi, installers area/build CMake, presets, toolchains, CI workflows area/core Core/ - the shared foundation; high blast radius os/windows Specific to Windows (MSVC, clang-cl, Winsock, IOCP) os/macos Specific to macOS (libc++, kqueue, launchd, pkg) os/linux Specific to Linux (glibc, epoll, systemd, deb/rpm) labels Oct 18, 2026
@christianparpart
christianparpart force-pushed the feature/pace-rename branch 5 times, most recently from d30f60f to cf110e7 Compare October 18, 2026 13:09
fastcached becomes pace-kv, fastcache-compile-node pace-node,
fastcache-cc pace-cc, fastcache-cli pacectl and fastcache-bench
pace-bench: their directories under src/apps, their targets and test
targets, the packaging files named after them, docs/tools/*.md, and
every reference to the binary. The bare word fastcached is read as the
daemon except where it is a path component (a directory, handled with
the runtime names) or a prefix (handled with the prefixes); the
firewall group's leading product name becomes Pace.

Generated by the rename tool, then edited by hand where its rules read
a name wrongly. Reproduced against this commit's parent on 2026-10-18,
with the exemption table this branch ends with
(scripts/brand-leftovers-exemptions.tsv):

    python -I rename.py rules-exe.tsv brand-leftovers-exemptions.tsv <worktree>

rules-exe.tsv (rule, scope, regex, replacement, count measured then):

    mv:app-node	src/apps/*	^src/apps/fastcache-compile-node/	src/apps/pace-node/	254
    mv:app-cc	src/apps/*	^src/apps/fastcache-cc/	src/apps/pace-cc/	127
    mv:app-cli	src/apps/*	^src/apps/fastcache-cli/	src/apps/pacectl/	111
    mv:app-bench	src/apps/*	^src/apps/fastcache-bench/	src/apps/pace-bench/	11
    mv:app-kv	src/apps/*	^src/apps/fastcached/	src/apps/pace-kv/	2
    mv:docs-tools	docs/tools/*	^docs/tools/fastcache-compile-node\.md$	docs/tools/pace-node.md	1
    mv:docs-tools-cc	docs/tools/*	^docs/tools/fastcache-cc\.md$	docs/tools/pace-cc.md	1
    mv:docs-tools-cli	docs/tools/*	^docs/tools/fastcache-cli\.md$	docs/tools/pacectl.md	1
    mv:linux-node	packaging/linux/*	/fastcache-compile-node\.	/pace-node.	3
    mv:linux-kv-user	packaging/linux/*	/fastcached-user\.service$	/pace-kv-user.service	1
    mv:linux-kv	packaging/linux/*	/fastcached\.(service|sysusers|tmpfiles)$	/pace-kv.\g<1>	3
    mv:config-node	packaging/config/*	/fastcache-compile-node\.yaml$	/pace-node.yaml	1
    mv:config-kv	packaging/config/*	/fastcached\.yaml$	/pace-kv.yaml	1
    mv:macos-uninstall	packaging/macos/*	/fastcached-uninstall\.sh\.in$	/pace-uninstall.sh.in	1
    mv:macos-paths	packaging/macos/*	/paths\.d\.fastcached$	/paths.d.pace	1
    mv:script-addr	scripts/*	/check-fastcache-addr-opt-out\.cmake$	/check-pace-addr-opt-out.cmake	1
    mv:script-cli-e2e	scripts/*	/fastcache-cli-e2e\.sh$	/pacectl-e2e.sh	1
    mv:bench-kv	bench/*	/fastcached_bench\.py$	/pace_kv_bench.py	1
    node	*	fastcache-compile-node	pace-node	992
    cli	*	fastcache-cli	pacectl	488
    cc	*	fastcache-cc	pace-cc	989
    bench	*	fastcache-bench	pace-bench	64
    kv-app-dir	*	(apps[/\\]+)fastcached\b(?![-_.])	\g<1>pace-kv	19
    kv-exe	*	(?i:fastcached)\.(?i:exe)\b	pace-kv.exe	91
    kv-unit-user	*	\bfastcached-user\.service\b	pace-kv-user.service	4
    kv-unit	*	\bfastcached\.(service|sysusers|tmpfiles)\b	pace-kv.\g<1>	34
    kv-bin	*	\bbin([/\\]+)fastcached\b(?![-_.])	bin\g<1>pace-kv	47
    kv-bench-script	*	\bfastcached_bench\.py\b	pace_kv_bench.py	13
    kv-uninstall	*	\bfastcached-uninstall\b	pace-uninstall	17
    kv-paths-d	*	\bpaths\.d\.fastcached\b	paths.d.pace	3
    kv-addr-script	*	check-fastcache-addr-opt-out	check-pace-addr-opt-out	7
    fw-group-code	src/Pace/Platform/Firewall.cpp	"fastcached: \{\}"	"Pace: {}"	1
    fw-group	*	fastcached: (?=FastCache)	Pace: 	17
    kv-shell-var	*	(?<=\$)(\{?)fastcached\b(?![-.])	\g<1>pace_kv	40
    kv-shell-assign	*	(?<![\w-])fastcached(?==)	pace_kv	15
    kv-script-flag	*	--fastcached\b(?![-_.])	--pace-kv	36
    kv-ninja-rule	*	__fastcached_	__pace-kv_	1
    kv-target-dir	*	\b(target|binDir\}|\{t\})([/\\]+)fastcached\b(?![-_.])	\g<1>\g<2>pace-kv	11
    kv-word	*	(?<![\w/\\.%-])fastcached(?![\w/\\-]|\.\w)	pace-kv	1297

By hand: every difference between the tool's output and this commit,
26 lines in 17 files.

  The package is pace, not the daemon binary:
  - .github/workflows/build.yml: `apt-get purge -y pace`.
  - scripts/rpm-package-e2e.sh: `rpm -q pace`, `dnf -y remove pace` and
    its failure message.
  - packaging/CMakeLists.txt: the macOS paths.d entry installs as `pace`.

  The socket holder is read by the kernel's 15-character comm, which the
  rule turned into a pattern no process carries:
  - .github/workflows/build.yml, scripts/rpm-package-e2e.sh: the adopted
    socket's holder is matched as `"pace-node",pid=`.

  Paths the daemon's name does not own:
  - .clang-tidy (two comment lines), scripts/check-tidy-header-filter.sh,
    scripts/local-gate.sh: the header filter's checkout segment is
    `pace[^/]*`.
  - scripts/node-config-file-e2e.sh: the per-user config directory is
    `$XDG/pace` (two lines).

  The product is Pace, the daemon pace-kv:
  - packaging/macos/welcome.html, readme.html and pace-uninstall.sh.in
    (three lines): what the package installs and the uninstaller removes.
  - src/apps/pace-node/NodeConfig.cpp (the service description and the
    help subject), src/apps/pace-node/main.cpp (its header) and
    scripts/check-cli-node-flags.sh (the same help subject): a compile
    worker for Pace.
  - cmake/portable/CompileCache.cmake, docs/internals/architecture.md,
    src/tests/CMakeLists.txt and .agent/rules/packaging-and-release.md
    (the example tag message): sentences about the project.

Signed-off-by: Christian Parpart <christian@parpart.family>
…ace_ of every metric

FASTCACHED_* (CMake options, cache variables, -D script inputs) and
FASTCACHE_* (environment variables) both become PACE_*; the CMake and
shell helpers fastcached_* and the metric names fastcached_* and
fastcache_* become pace_*; and the CamelCase helper names
(FastCachedFoo, FastCacheNodeFoo, FastcacheWireOnly) drop the brand to
Pace/PaceNode. Checked before the run: no two old metric names collapse
onto one. One pair of names DOES share a suffix --
FASTCACHED_SOURCE_DIR (a -D input to the check scripts) and
FASTCACHE_SOURCE_DIR (the launcher's environment variable) both become
PACE_SOURCE_DIR -- and no file names both, so they stay in separate
namespaces (a CMake variable and an environment variable).

Generated by the rename tool, with one hand edit. Reproduced against
this commit's parent on 2026-10-18, with the exemption table this branch
ends with (scripts/brand-leftovers-exemptions.tsv):

    python -I rename.py rules-prefix.tsv brand-leftovers-exemptions.tsv <worktree>

rules-prefix.tsv (rule, scope, regex, replacement, count measured then):

    upper-d	*	(?:(?<![A-Za-z0-9])|(?<=-D)|(?<=\\n))FASTCACHED_	PACE_	3054
    upper	*	(?:(?<![A-Za-z0-9])|(?<=-D)|(?<=\\n))FASTCACHE_	PACE_	1524
    lower-d	*	(?:(?<![A-Za-z0-9])|(?<=\\n))fastcached_	pace_	1655
    lower	*	(?:(?<![A-Za-z0-9])|(?<=\\n))fastcache_	pace_	709
    camel-split	*	' FastCached'\+'ImagePath:'	' Pace'+'ImagePath:'	2
    camel-node	*	FastCacheCompileNode(?=[A-Z_])	PaceNode	7
    camel-d	*	FastCached(?=[A-Z_])	Pace	1251
    camel	*	FastCache(?=[A-Z_])(?!CompileNode\b)	Pace	618
    camel-lower	*	Fastcache(?=[A-Z_])	Pace	34
    camel-kv-word	*	\bFastcached\b	PaceKv	42
    camel-embedded-kv	*	(?<=[a-z])Fastcached\b	PaceKv	2

By hand: every difference between the tool's output and this commit,
3 lines in 1 file. packaging/windows/service-actions.xml's three
CPackWiXFragment ids name CPack's component ids, which spell a `-` in a
file name as `_` and which the tool's rules cannot derive:
CM_CP_Daemon.bin.pace_kv.exe, CM_CP_Node.bin.pace_node.exe and
CM_CP_Cli.bin.pacectl.exe.

Signed-off-by: Christian Parpart <christian@parpart.family>
@christianparpart
christianparpart force-pushed the feature/pace-rename branch 4 times, most recently from 75aca83 to 0cf2700 Compare October 18, 2026 14:42
…arry the new names

The Windows services FastCached and FastCacheCompileNode are pace-kv and
pace-node; the launchd labels are software.lastrada.pace-kv and
software.lastrada.pace-node; the accounts are pace-kv / pace-node
(_pace-kv / _pace-node on macOS) and the node's state directory is
pace-node everywhere. The configuration directory is the product's
(/etc/pace, %ProgramData%\pace, %APPDATA%\pace, ~/.config/pace) and
holds pace-kv.yaml and pace-node.yaml; kv state is /var/lib/pace-kv;
the installer's registry state is HKLM\SOFTWARE\Pace; the macOS prefix
is /opt/pace; the DNS SRV record is _pace._tcp.

Generated by the rename tool, then edited by hand. Reproduced against
this commit's parent on 2026-10-18, with the exemption table this branch
ends with (scripts/brand-leftovers-exemptions.tsv); every count matches:

    python -I rename.py rules-runtime.tsv brand-leftovers-exemptions.tsv <worktree>

rules-runtime.tsv (rule, scope, regex, replacement, count measured then):

    svc-node	*	\bFastCacheCompileNode\b	pace-node	207
    svc-kv	*	\bFastCached\b	pace-kv	280
    label-node	*	software\.lastrada\.fastcachecompilenode\b	software.lastrada.pace-node	4
    label-e2e	*	software\.lastrada\.fastcachede2e\b	software.lastrada.pacee2e	1
    label-kv	*	software\.lastrada\.fastcached\b	software.lastrada.pace-kv	24
    node-state	*	(?<![\w-])fastcache-node\b	pace-node	247
    mac-account-kv	*	(?<![\w-])_fastcached\b(?![-.])	_pace-kv	53
    mac-account-node	*	(?<![\w-])_fastcache-node\b	_pace-node	0
    ci-checkout	*	\b(a|work)([/\\]+)fastcached([/\\]+)fastcached\b	\g<1>\g<2>pace\g<3>pace	3
    dir-etc-kv-yaml	*	\b(etc[/\\]+)fastcached([/\\]+)fastcached\.yaml	\g<1>pace\g<2>pace-kv.yaml	41
    dir-etc	*	\b(etc[/\\]+)fastcached\b(?![-_.])	\g<1>pace	57
    dir-opt	*	\b(opt[/\\]+)fastcached\b(?![-_])	\g<1>pace	77
    dir-varlib	*	\b(lib[/\\]+)fastcached\b(?![-_.])	\g<1>pace-kv	29
    dir-state	*	\b(state[/\\]+)fastcached\b(?![-_.])	\g<1>pace-kv	2
    dir-caches	*	\b(Caches[/\\]+)fastcached\b(?![-_.])	\g<1>pace-kv	3
    dir-programfiles	*	(Program Files[/\\]+|ProgramFiles64Folder\]|PROGRA~1[/\\]+)fastcached\b(?![-_.])	\g<1>Pace	16
    dir-programdata	*	(ProgramData%?[/\\]+)fastcached\b(?![-_.])	\g<1>pace	38
    dir-appdata	*	((?:LOCAL)?APPDATA%?[/\\]+)fastcached\b(?![-_.])	\g<1>pace	5
    dir-config	*	((?:\.config|CONFIG_HOME)[/\\]+)fastcached\b(?![-_.])	\g<1>pace	20
    dir-cache	*	(\.cache[/\\]+)fastcached\b(?![-_.])	\g<1>pace	12
    dir-cpm	*	\bfastcached([/\\]+)cpm\b	pace\g<1>cpm	2
    dir-doc	*	(doc[/\\]+)fastcached\b(?![-_.])	\g<1>pace	2
    dir-registry	*	(SOFTWARE[/\\]+)fastcached\b(?![-_.])	\g<1>Pace	82
    cpm-home	*	_fastcachedCpmHome	_paceCpmHome	9
    sysusers-conf	*	\b(sysusers\.d|tmpfiles\.d)([/\\]+)fastcached\.conf	\g<1>\g<2>pace-kv.conf	4
    kv-yaml	*	(?<![\w-])fastcached\.yaml	pace-kv.yaml	136
    kv-files	*	(?<![\w-])fastcached\.(log|err\.log|out\.log|pid|plist|conf|cowtree)\b	pace-kv.\g<1>	19
    kv-msi	*	(?<![\w-])fastcached\.msi\b	pace.msi	7
    kv-suffix	*	(?<=[A-Za-z0-9]_)fastcached\b	pace_kv	15
    kv-camel-lower	*	\bfastcached(?=[A-Z])	paceKv	20
    camel-lower	*	\bfastcache(?=[A-Z])	pace	6
    sign-glob	*	bin/fastcache\*	bin/pace*	2
    srv-record	*	_fastcache\._tcp	_pace._tcp	26
    label-smoke	*	software\.lastrada\.fastcachedsmoke\b	software.lastrada.pacesmoke	1
    srv-label	*	(?<![\w])_fastcache\b	_pace	1
    resp-server-name	*	\$10\\r\\nfastcached\\r\\n	$7\\r\\npace-kv\\r\\n	3
    camel-ellipsis	*	SetFastCache\.\.\.Argument	SetPace...Argument	1
    kv-cmake-dir	*	(?<=CMakeFiles/)fastcached(?=\.dir)	pace-kv	1
    kv-binary-path	*	(\}/|path-to-|Logs/|base/|candidate/|(?<![\w.])\./)fastcached\b(?![-_.])	\g<1>pace-kv	15
    paths-d	*	\bpaths\.d([/\\]+)fastcached\b	paths.d\g<1>pace	5
    unit-state	*	%S/fastcached\b	%S/pace-kv	1
    unit-config	*	%E/fastcached\b	%E/pace	1
    option-prefix-regex	*	\(FASTCACHED\|ENABLE\)	(PACE|ENABLE)	4
    kv-shell-upper	*	\bFASTCACHED\b	PACE_KV	31
    description	*	\bfastcache compile\b	Pace compile	4
    kv-only	*	\bfastcached-only\b	pace-kv-only	10
    node-config-dir	*	((?:APPDATA|ProgramData)%?[/\\]+|(?:CONFIG_HOME|\.config)[/\\]+)pace-node([/\\]+)pace-node\.yaml	\g<1>pace\g<2>pace-node.yaml	6

By hand: every difference between the tool's output and this commit,
52 lines in 10 files.

  - src/Pace/Config/DefaultConfigPath.{cpp,hpp}: the config lookup rows
    name the product directory once (pace/{app}.yaml, not {app}/{app}.yaml).
  - scripts/lib/MsiServiceTable.psm1 and .github/workflows/build.yml: the
    PowerShell hashtables keyed on a service name quote the now-hyphenated
    keys.
  - packaging/windows/service-actions.xml: the %ProgramData% directory is
    the product's, `pace`.
  - packaging/CMakeLists.txt: the Windows configuration templates are
    installed under the component the app table sets for each app's
    directory (`PACE_COMPONENT_OF_pace-kv`). The rules wrote `pace_kv`,
    a property nothing sets, so the MSI shipped no daemon template. A
    built app with no component is now refused at configure time.
  - .github/workflows/build.yml: the seeded-configuration check prints
    the file's size and first lines before it refuses.
  - scripts/local-gate.sh, scripts/tidy-sweep.sh,
    scripts/check-clang-tidy-version.sh and
    .agent/rules/build-and-toolchain.md: the gate's cache and the
    clang-tidy install are the product's directories (`pace/gate`,
    `pace/clang-tidy`), where check-clang-tidy-version.sh looks.

Signed-off-by: Christian Parpart <christian@parpart.family>
Every github.com/LASTRADA-Software/fastcached link and slug is
LASTRADA-Software/pace (the repository is renamed before this lands),
the Pages site is lastrada-software.github.io/pace, and every remaining
fastcached-/fastcache- name (artifact names, scratch and lock names,
worktree directories in examples) and bare product word is pace. After
this commit the residual listing outside the exemption table is empty:

    python -I rename.py --residual brand-leftovers-exemptions.tsv <worktree>   ->  RESIDUAL 0

Generated by the rename tool, then edited by hand. Reproduced against
this commit's parent on 2026-10-18, with the exemption table this branch
ends with (scripts/brand-leftovers-exemptions.tsv), whose rows keep three
measured transcripts naming the checkout they were taken in:

    python -I rename.py rules-prose.tsv brand-leftovers-exemptions.tsv <worktree>

rules-prose.tsv (rule, scope, regex, replacement, count measured then):

    repo-link	*	github\.com([/:])LASTRADA-Software/fastcached\b	github.com\g<1>LASTRADA-Software/pace	866
    repo-slug	*	\bLASTRADA-Software/fastcached\b	LASTRADA-Software/pace	13
    pages-link	*	lastrada-software\.github\.io/fastcached\b	lastrada-software.github.io/pace	10
    hyphen-d	*	(?<![\w])fastcached-	pace-	181
    hyphen	*	(?<![\w])fastcache-	pace-	47
    camel-tail	*	(?<=_)FastCache\b	Pace	2
    word-d	*	\bfastcached\b	pace	71
    word	*	\bfastcache\b	pace	28

By hand: every difference between the tool's output and this commit,
10 lines in 7 files.

  The product's titles read Pace rather than the daemon's name:
  - README.md, AGENT.md, docs/index.md and bench/README.md: the title
    (and docs/index.md's first sentence).
  - mkdocs.yml: site_name and site_author.
  - .github/workflows/build.yml: the draft release name.

  Where the bare word meant the daemon binary, not the product:
  - CMakeLists.txt: the install path /usr/local/bin/pace-kv.
  - README.md: the link to the "Using pace-kv as an sccache backend"
    heading, so the anchor resolves.

Signed-off-by: Christian Parpart <christian@parpart.family>
docs/upgrading-to-pace.md names every renamed binary, service, account,
label, variable, option, metric and path, then walks the switch per
platform: uninstall fastcached (its configs stay on disk), install
Pace, copy the settings into pace-kv.yaml / pace-node.yaml, rename the
FASTCACHE_* variables, re-enroll every fleet member, the Lastrada
checklist, and the documentation's new address.

Keeping a node's identity by moving fastcache-node to pace-node is not
offered on any platform. `--install-service` hands over the directory
but not the files already in it -- Windows refuses a key file owned by
the old service SID (FileTrust's ownership check), and macOS chowns the
directory alone -- and the Linux path through systemd's StateDirectory=
was never tested; the fleet is four machines, so re-enrolling is the
supported step.

Linked from README.md and the documentation's navigation.

Signed-off-by: Christian Parpart <christian@parpart.family>
…hed is installed

Pace's packages are named pace (install directory Pace) and the MSI
carries a NEW upgrade code. Reusing fastcached's would make the 0.6.0
install a major upgrade, and a removal nested in an upgrade does not run
its uninstall-service actions (NOT UPGRADINGPRODUCTCODE): fastcached's
services would stay registered over binaries the upgrade deleted. So
fastcached is detected and refused, with the remedy named, everywhere:

- MSI: an Upgrade row (OnlyDetect) on fastcached's code
  581D183D-47A3-44FC-97E9-4B5491E792D8 sets RETIRED_FASTCACHED_PRODUCT,
  and a launch condition refuses while it is set: "fastcached is
  installed. Uninstall it (Settings > Apps > fastcached), then install
  Pace." `Installed` keeps it off Pace's own repair and removal.
- deb / rpm: Conflicts: fastcached, and no Replaces/Obsoletes, which
  would remove fastcached as a side effect and skip its teardown.
- macOS: a Runtime preinstall refuses while pkgutil lists a
  software.lastrada.fastcached receipt, naming
  /opt/fastcached/bin/fastcached-uninstall; read from a string, never
  `pkgutil | grep -q`.

CI covers the Pace product only. "Refused while fastcached is
installed, installed once it is not" installs the real 0.5.0 MSI,
expects Pace's install to fail with the condition's message and leave
no Pace product, uninstalls 0.5.0 and installs and removes Pace. The
upgrade step loses its 0.3.0 starting point and upgrades between two
builds of Pace; the latest-release leg skips a release whose MSI
carries fastcached's code, so the first Pace release turns it on.

Not run locally: this host has no WiX, so the MSI and the CI step are
exercised by CI only.

Signed-off-by: Christian Parpart <christian@parpart.family>
…Agent

The cache daemon shipped a user unit and a LaunchAgent; the compile node
shipped neither. packaging/linux/pace-node-user.service is the per-user
node: pace-kv-user.service's hardening (without MemoryDenyWriteExecute,
which the system node unit also leaves out, since compilers inherit
it), ExecStart=/usr/bin/pace-node with no --config,
StateDirectory=pace-node, a RuntimeDirectory working directory so a
compile never records `/`, WantedBy=default.target, and no socket
activation -- the node binds its own ports and its guards stay. It is
a row of the asset table, installed as pace-node.service in the systemd
user directory, and a row of check-node-working-directory's working-
and state-directory tables.

The node's LaunchAgent is the one `pace-node --install-service
--service-scope=user` writes, labelled software.lastrada.pace-node.

`[defaults][user-unit]` holds both to NodeDefaults' per-user default:
the unit's StateDirectory= is read out of the shipped file and must be
NodeStateDirectoryName; on POSIX the node resolves $XDG_STATE_HOME/that
both by itself and from the unit's handover; and the user-scope plist
and registration hand over no STATE_DIRECTORY and no --cluster-dir.

Signed-off-by: Christian Parpart <christian@parpart.family>
… name, never read

Not a bridge: no value under an old name is read. Two places where the
old spelling would otherwise be ignored in silence now say so:

- Environment. pace-cc and pace-node print one stderr line while any
  FASTCACHE_* variable is set, naming each: "pace-cc: FASTCACHE_ADDR is
  no longer read; rename it to PACE_* (docs/upgrading-to-pace.md)".
  Without it, a Lastrada build exporting only FASTCACHE_ADDR stops
  distributing and nothing says why. The decision is a header-only pure
  function over names (Cli/RetiredEnvironment.hpp, which the launcher
  compiles in without linking Pace); the names come from the one
  environment seam, which gains EnvironmentVariableNames(). Exit status
  and behaviour are otherwise unchanged.
- Configure. The top-level CMakeLists.txt includes
  cmake/RetiredOptions.cmake right after project() and fails when the
  cache holds a FASTCACHED_* entry: "renamed PACE_* and are no longer
  read: delete this build tree and configure again".
  cmake/portable/CompileCache.cmake does not get it: that module may
  never fail a configure. The decision is split out
  (pace_retired_cache_entries) so `ctest -R retired-cmake-options`
  drives it; neutered to match FASTCACHED_ anywhere, its PACE_ case
  goes red naming MY_FASTCACHED_THING.

The project is `pace` rather than the daemon's name. Both refusals are
removed in 0.8.0 (#1713, linked from build-and-toolchain.md's Open
work).

Signed-off-by: Christian Parpart <christian@parpart.family>
…exception named

`ctest -R brand-leftovers` asks the tracked-files seam for every
first-party file (declining the third-party roots, which it names) and
refuses any line spelling the old product name, case-insensitively, that
no row of scripts/brand-leftovers-exemptions.tsv covers -- and any
tracked PATH carrying it, which is never exempt. A row (path glob, regex,
reason) that covers nothing is refused as stale. The rename tool read the
same table to know what it must not rewrite. It prints what it scanned,
what it exempted and how many rows it used: today 1685 files, 192
matches, 20 of 20 rows.

The rows: the signing labels, jitbit/FastCache (another project), the
upgrade guide and its two pointers, the three installer refusals (MSI,
deb/rpm Conflicts, macOS preinstall), and the two refusals of #1713 with
their tests, which go with them in 0.8.0. The MSI refusal's CI steps
move into scripts/msi-refuses-retired-product.ps1 so build.yml carries
the old name nowhere, and the packaging comments name it only where an
installer must.

`brand-leftovers-selftest` drives five synthetic git trees: a planted
leftover and a stale row refuse, an exempted label and a clean tree
pass, a branded path refuses; it asserts git mode and prints how many
cases ran. Neutered on the real tree, a comment naming the old product
in src/Pace/Core/Base64.hpp is reported as Base64.hpp:83.

Signed-off-by: Christian Parpart <christian@parpart.family>
`Pace::` is five characters shorter than `FastCache::`, and the
executable and option names changed length too, so 76 of the 1158 C++
files the rename touched wrap differently under the pinned formatter
(.clang-format-version). Formatting only: produced by running
clang-format 22.1.8 -i over exactly the C++ files changed since the
branch point, nothing edited by hand.

Signed-off-by: Christian Parpart <christian@parpart.family>
Each of these passed before the rename and failed after it, found by
running the four suites at the tip:

- A firewall group is `Pace: <service>` (FirewallGroupFor), and the
  tests that spelled one literally (`fastcached: Probe`) were renamed by
  the daemon's word to `pace-kv: Probe`: Firewall_test,
  ServiceControl_test, MsiServiceTable.psm1's self-test and the MSI
  job's firewall step say `Pace: ` again.
- One namespace now serves the daemon's and the node's series, so the
  two documentation checks cannot split them by prefix any more: each
  asks that what its binary renders is documented on EITHER page and
  what its page names is rendered by EITHER binary. And a series name
  starts a token: `pace_` also occurs inside `keyspace_reclaim`, which
  the scan read as an undocumented series.
- The live-stats layout digest folds every series NAME, so the pin
  moves (0x603edf728d83daf4); that digest is the detection, so clients
  and nodes upgrade together as for every other move.
- The SRV fixture's compression pointer counted `_fastcache`'s 11 bytes;
  `_pace` is 6.
- `"\"pace-kv\" --daemon"`: the escaped quote kept the daemon's word off
  the executable, and the product rule made it `pace`.
- Four shipped .service units now, with pace-node-user.service.
- EnvExpand's input and expectation name the same directory again.
- The dashboard's narrow title bar is asked at 37 cells: `pace-kv` is
  three shorter than the name it replaced, and at 40 the version fits.

FileTrust's foreign-owned-entry case still fails on this host, as it
does on master (#1683).

Signed-off-by: Christian Parpart <christian@parpart.family>
- scripts/pacectl-e2e.sh is executable again: the rename moved it and
  dropped its mode (script-modes).
- XML forbids `--` inside a comment, and the refusal's comment in
  service-actions.xml carried two (wix-fragment,
  msi-custom-action-commands).
- check-retired-options.cmake states its policies, as every `cmake -P`
  script must (script-check-signals).
- node-working-directory-selftest's good tree carries the per-user node
  unit its check's tables now name.
- MsiServiceTable.psm1's self-test expects pace-kv.exe (the regex escape
  kept the executable rule off the old name), and its real 7031 event's
  binary data -- the service name in UTF-16LE -- is re-encoded for
  pace-node; the self-test passes its 183 cases.
- The app tree in AGENT.md and source-map.md names the daemon's
  directory pace-kv/, as every other row names its app's.
- Two comments of the previous commit spelled the old prefixes, which
  brand-leftovers rightly refused.

Signed-off-by: Christian Parpart <christian@parpart.family>
@christianparpart
christianparpart marked this pull request as ready for review October 18, 2026 16:35
@christianparpart
christianparpart merged commit 97991fd into master Oct 18, 2026
61 of 62 checks passed
@christianparpart
christianparpart deleted the feature/pace-rename branch October 18, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build CMake, presets, toolchains, CI workflows area/compile-cache CompileCache/, the 0xFC wire, the executor, PathCanon area/core Core/ - the shared foundation; high blast radius area/distributed Distributed/, apps/fastcache-compile-node/ - dispatch, workers, scheduler area/launcher apps/fastcache-cc/ - the compiler launcher and its cache key area/packaging packaging/, CPack, deb/rpm/pkg/msi, installers area/platform Platform/, Config/, Cli/ - service registration, config lookup, the CLI table area/storage Cache/, CowTree/ - engine, LRU, layered, sharded, compression os/linux Specific to Linux (glibc, epoll, systemd, deb/rpm) os/macos Specific to macOS (libc++, kqueue, launchd, pkg) os/windows Specific to Windows (MSVC, clang-cl, Winsock, IOCP) type/chore Dependencies, CI plumbing, release mechanics, repo hygiene

Projects

None yet

Development

Successfully merging this pull request may close these issues.

project and tool naming

1 participant