docs: record that the session-start hook stores an absolute path (task 0042)
Resolve the nix-flake-packaging spec's open verification item by observation rather than inference, and act on the unfavourable answer. `resolvePortableHookCommand` in axi-sdk-js returns the bare binary name only when a PATH entry realpath-matches the entrypoint. npm symlinks its bin entry straight at dist/main.js and satisfies that; Nix installs a generated wrapper script whose realpath is the wrapper, so the absolute store path is recorded instead. Verified by probing the SDK with both install shapes and by driving the flake-built binary against a temporary HOME. The path is content-addressed, so it moves on every rebuild and is eventually collected, and a session-start hook that cannot execute fails silently. The mitigation is documentation, per the decision recorded when the item was opened: the setup help text now says to re-run `setup hooks` after an upgrade. How the setup command constructs the hook is deliberately unchanged. Preferring the bare name is the right answer for every wrapper-based install, not a Nix special case, so it belongs in a successor task with its own ADR alongside the related `isManagedHook` substring defect. package.nix's postUnpack rename therefore stays; its comment no longer promises this task will remove it.
This commit is contained in:
@@ -200,15 +200,30 @@ The workflow keeps its container-and-npm shape, deliberately preserving the GitH
|
||||
|
||||
## Further Notes
|
||||
|
||||
### Open verification item
|
||||
### Resolved verification item: the hook records the absolute path under Nix
|
||||
|
||||
The `setup` command's hook installation passes the SDK both an absolute path to the running entrypoint and the bare binary name.
|
||||
Under Nix the absolute path is content-addressed: it changes on every rebuild and is eventually garbage-collected, so a hook recording it would break silently, since a session-start hook that cannot execute simply does not run.
|
||||
The bare binary name strongly suggests the SDK prefers search-path resolution and treats the absolute path as a fallback, which would make this a non-issue, but this could not be confirmed during design because the dependency was not installed.
|
||||
The design-time hope was that the SDK prefers search-path resolution and treats the absolute path as a fallback, which would have made this a non-issue.
|
||||
It was verified against the installed dependency and against a real Nix build, and the answer is the unfavourable one: **under Nix the absolute store path is recorded**, even with the binary on `PATH`.
|
||||
|
||||
The decision is to verify before acting.
|
||||
If the SDK does record the absolute path, the immediate mitigation is documenting that the hook setup should be re-run after an upgrade.
|
||||
Changing the `setup` command to prefer the bare name would then become a separate task with its own ADR — justified on the grounds that a stable search-path name is more robust for *every* installation method, and explicitly not as a special case that detects Nix store paths in application code.
|
||||
The SDK's `resolvePortableHookCommand` returns the bare name only when some `PATH` entry *realpath-matches* the entrypoint, and the absolute path otherwise.
|
||||
That test is what splits the two installation methods, and the split is a property of how each one puts the binary on `PATH`:
|
||||
|
||||
- **npm** symlinks the `bin` entry directly at the entrypoint, so the realpath comparison succeeds and the bare name is recorded.
|
||||
- **Nix** installs the `bin` entry as a *generated wrapper script* that invokes `node <path>` — `nodejsInstallExecutables` inside `npmInstallHook`, plus this package's own `makeWrapper` layer for `git` and `tea`.
|
||||
A wrapper's realpath is the wrapper, never the entrypoint, so the comparison cannot succeed and the absolute path is recorded.
|
||||
|
||||
So the preference for the bare name is real, but it is unreachable through any wrapper-based install.
|
||||
It is not that Nix was overlooked; it is that the mechanism keys on a filesystem relationship only the symlink shape has.
|
||||
|
||||
The mitigation is therefore documentation, per the decision recorded when this item was opened: the `setup` command's help text states that `setup hooks` must be re-run after an upgrade.
|
||||
The failure it guards against is silent — a session-start hook that cannot execute simply does not run, so a user gets no error, only the quiet absence of their ambient dashboard.
|
||||
|
||||
Changing the `setup` command to prefer the bare name remains a separate task with its own ADR, justified on the grounds that a stable search-path name is more robust for *every* installation method, and explicitly not as a special case that detects Nix store paths in application code.
|
||||
Two findings feed that future task.
|
||||
First, the mitigation above is documentation against a silent failure, which is the weakest kind of fix.
|
||||
Second, a related defect shares the same line: `isManagedHook` recognises its own hook by testing whether the recorded command string *contains* the marker `gitea-axi`, so an entrypoint path lacking that substring makes `setup hooks` append a duplicate rather than update in place, contradicting the idempotency its help text promises.
|
||||
That coupling is why `package.nix` renames its build tree in `postUnpack`; the rename can be deleted once the hook no longer depends on the entrypoint path.
|
||||
|
||||
### Verified during design
|
||||
|
||||
|
||||
Reference in New Issue
Block a user