The README's install line failed: the package was never published, and nothing told npm where the @extant2000 scope lives. A tag like v1.2.3 now publishes to this project's registry with CI_JOB_TOKEN, and the README sets the scope's registry before installing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.3 KiB
Markdown
86 lines
3.3 KiB
Markdown
# HandOff
|
|
|
|
Decides whether a capability can be operated by someone other than the
|
|
person who built it, by looking at what it depends on.
|
|
|
|
## What it does and why
|
|
|
|
Handover is usually treated as a documentation problem, but documentation is the smaller part of it. **Operability is the absence of dependence on a specific person or
|
|
machine.** A thorough runbook does not remove a dependency. It describes one.
|
|
|
|
HandOff takes the list of things a capability depends on (credentials,
|
|
runtimes, knowledge, access, data), what each one is bound to, and what the
|
|
recipient would use instead. It checks them for three failures.
|
|
|
|
1. A personal credential doing institutional work. For example, several
|
|
products deploy with one engineer's personal access token. No runbook
|
|
transfers that: the recipient cannot obtain it, and it stops working when
|
|
the account goes away. It is reported as a critical blocker, not a gap in
|
|
the docs.
|
|
2. A dependency on a machine instead of a role. A script that hard-codes a
|
|
path on one laptop runs on that laptop. It works perfectly, forever, for
|
|
one person.
|
|
3. A substitute nobody has exercised. This one survives every review,
|
|
because it is written down and so looks done. A runbook nobody but its
|
|
author has followed is a draft, so it is reported as not assessed.
|
|
|
|
An account binding with no recorded way for the recipient to get their own
|
|
account fails at high severity. Operating knowledge that exists only in
|
|
someone's head fails too.
|
|
|
|
## Readiness is the worst dependency, never the average
|
|
|
|
One personal credential blocks a transfer however good everything else is.
|
|
Averaging is how that blocker disappears behind nine green rows.
|
|
|
|
| Readiness | When |
|
|
|---|---|
|
|
| `transferable` | Every dependency is unbound or has a substitute someone else has exercised. |
|
|
| `blocked` | At least one dependency cannot be handed over. |
|
|
| `unproven` | Nothing is blocked, but at least one substitute has never been exercised. |
|
|
| `unknown` | No dependencies were listed. The capability was assumed, not examined. |
|
|
|
|
## Usage
|
|
|
|
```ts
|
|
import { assess, formatHandOff, type Capability } from '@extant2000/hand-off'
|
|
|
|
const capability: Capability = {
|
|
name: 'release pipeline',
|
|
recipient: 'the partner ops team',
|
|
dependencies: [{
|
|
name: 'deploy-token', kind: 'credential',
|
|
coupling: 'person', boundTo: 'alice',
|
|
substitute: 'a group deploy token per project',
|
|
substituteVerified: true,
|
|
where: 'config/deploy.env',
|
|
}],
|
|
}
|
|
|
|
const { readiness, reason, blockers, unproven } = assess(capability)
|
|
console.log(formatHandOff(capability)) // report in the evidence-record format
|
|
```
|
|
|
|
`substituteVerified` means someone other than the author has followed the
|
|
substitute. Leaving it out counts as `false`, because an unexercised
|
|
substitute is a claim. The example above is `transferable`; drop the
|
|
substitute and it becomes `blocked`.
|
|
|
|
`coupling` is one of `person`, `machine`, `account` or `none`. `kind` is one
|
|
of `credential`, `runtime`, `knowledge`, `access` or `data`. Every finding
|
|
cites the dependency's `where`. The library is pure: no clock and no I/O.
|
|
|
|
## Install
|
|
|
|
The package is published to the GitLab package registry, so point the
|
|
`@extant2000` scope there first:
|
|
|
|
```
|
|
npm config set @extant2000:registry https://gitlab.com/api/v4/packages/npm/
|
|
npm install @extant2000/hand-off
|
|
```
|
|
|
|
## License
|
|
|
|
MIT. See [LICENSE](LICENSE).
|