@assuredloop/cli 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,243 +1,291 @@
1
1
  # AssuredLoop
2
2
 
3
3
  AssuredLoop keeps an AI focused on one change. It holds together:
4
- - the owner's words;
5
- - the organized requirement the owner signs off;
6
- - the current consolidated spec, the baseline: Markdown sections in `specs/`,
7
- each headed by an ID such as `## [INV-3] Dates`; and the change to it;
8
- - the decisions;
9
- - the code and tests that came with it.
10
-
11
- A change to a promise keeps these records in a request, the folder
12
- `requests/<name>/`.
13
-
14
- Its command, `al`, gathers and checks these records and says what to do next.
15
- It gives hints; it blocks nothing but its own `consolidate` and `conclude`.
4
+ - the owner's words, as snapshots;
5
+ - the organized requirement that the owner signs;
6
+ - the consolidated spec in `specs/`: the system now, the promises and the
7
+ lasting design, each paragraph with a hidden ID;
8
+ - each change's own design, its change spec, beside its request;
9
+ - the decisions and the ADRs;
10
+ - the code, the tests and the documents that came with the change.
11
+
12
+ Its command, `al`, keeps these records, checks them, and says what to do
13
+ next. It refuses only in its own `al conclude`. Every other check is a hint;
14
+ a project that wants blocks turns on `al check --strict` in its CI.
15
+
16
+ AssuredLoop is not a lifecycle tool. It has no phases, no roles, no task
17
+ states and no approvals beyond the owner's sign-off. How and when you design,
18
+ test and review is your project's way of working.
16
19
 
17
20
  ## Install
18
21
 
19
- It needs Node 24 or newer and git 2.31 or newer, and nothing else. Install
20
- the npm package `@assuredloop/cli`, which puts `al` on your PATH:
22
+ Version 0.2.0 is v4. It is a breaking release: it does not read the records
23
+ of 0.1.0. To move a project from 0.1.0, see "From 0.1.0" in "Adopting
24
+ AssuredLoop".
25
+
26
+ It needs Node 24 or newer and git 2.31 or newer. Install the npm package
27
+ `@assuredloop/cli`, which puts `al` on your PATH:
21
28
 
22
29
  npm install --global @assuredloop/cli
23
30
 
24
- To pin a version, name it: `npm install --global @assuredloop/cli@0.1.0`.
25
- `al --version` prints the version and the folder it runs from.
31
+ The recommended install adds the optional package `@assuredloop/search`
32
+ beside it, for search at level 2 (see "Search"):
33
+
34
+ npm install --global @assuredloop/cli @assuredloop/search
35
+
36
+ To pin a version, name it: `npm install --global @assuredloop/cli@<version>`.
37
+ Give both packages the same version.
26
38
 
27
- The package carries the skill. Its folder, `<dir>` below, is
28
- `$(npm root -g)/@assuredloop/cli`, so the skill is at
29
- `$(npm root -g)/@assuredloop/cli/skills/assuredloop/SKILL.md`. Then add one
30
- line to the project's AGENTS.md:
39
+ The package carries the skill, at
40
+ `$(npm root -g)/@assuredloop/cli/skills/assuredloop/SKILL.md`. Add one line to
41
+ the project's AGENTS.md:
31
42
 
32
43
  ```
33
- AssuredLoop keeps this project's requests and spec: before work that changes a promise, read <dir>/skills/assuredloop/SKILL.md and run `al context`.
44
+ AssuredLoop keeps this project's requests and spec: before work that changes the spec, read <dir>/skills/assuredloop/SKILL.md and run `al context`.
34
45
  ```
35
46
 
36
47
  In a shared repo whose contributors install `al` in different places, copy
37
- `skills/assuredloop/SKILL.md` from `<dir>` at the pinned version into the
38
- project, for example as `.claude/skills/assuredloop/SKILL.md`. Name that path
39
- in the AGENTS.md line, say in the commit which version it came from, and copy
40
- it again when you re-pin.
41
-
42
- To work on `al` itself, use a clone in place of the npm package:
43
-
44
- git clone https://github.com/guwenqing/assuredloop <dir>
45
- npm install --global <dir>
46
-
47
- The global `al` links to `<dir>`, so it follows whatever `<dir>` checks out.
48
- To pin a commit, check out its SHA in a clone of its own (`git -C <dir>
49
- checkout <sha>`) and run `node <dir>/bin/al.js` in place of `al`; it needs no
50
- install, having no dependencies. From a clone, `al --version` also prints the
51
- commit.
52
-
53
- To run `al check --strict` in CI, check the project out with its whole history
54
- (`fetch-depth: 0`), install the pinned version
55
- (`npm install --global @assuredloop/cli@0.1.0`), and run `al check --strict`. A
56
- checkout with no main ref says
57
- `no main to compare with, so no commits were checked`: it compares none of the
58
- branch's commits with main, though its other checks, such as duplicate IDs in
59
- the working tree, still run and can fail. A shallow clone that has
60
- `origin/main` does not print that line, but reads no history before its
61
- shallow boundary.
48
+ the skill at the pinned version into the project, for example as
49
+ `.claude/skills/assuredloop/SKILL.md`. Name that path in the AGENTS.md line,
50
+ and say in the commit which version it came from.
51
+
52
+ Search at level 2 needs the optional package `@assuredloop/search` (see
53
+ "Search"). Install it in the project, or beside `al`.
54
+
55
+ ## The model in one page
56
+
57
+ - **Paragraphs and markers.** Every paragraph of a spec doc has an ID in a
58
+ hidden HTML comment on its own line before it, with a blank line before and
59
+ after it. The marker holds the ID, the kind and the links:
60
+
61
+ ```markdown
62
+ <!-- INV-41 rule serves:invoice-exports/R2 builds-on:INV-12 -->
63
+
64
+ The export link MUST expire 30 minutes after the email is sent.
65
+ ```
66
+
67
+ GitHub does not show the marker. The ID is one flat number per file, and
68
+ it is never used again. `al` computes a display number, for example
69
+ `INV-41 (2.3:4, in Export links)`, which can change when text moves.
70
+ - **Kinds.** Promise kinds (purpose, scope, rule, limit, definition): a
71
+ change needs a signed requirement that covers it. Design kinds (component,
72
+ interface, data, flow, choice) and `approach` (how one change is built):
73
+ a change needs review. Informative kinds (rationale, example, open), `note`
74
+ (headings and connecting text), and the change-only kinds (plan, step,
75
+ migration).
76
+ - **A request** is the folder `requests/<name>/`: `origin/` (the owner's words
77
+ and the sign-offs, as snapshots with SHA-256), `request.md` (the dialog, the
78
+ organized requirement R1…, the decisions D1…) and, from path 2, `spec.md`,
79
+ the change spec, with IDs SP-1, SP-2…
80
+ - **Records** in `.assuredloop/records/`, committed to git: one per request
81
+ (its sources, requirement versions, sign-offs, decisions, tasks, the
82
+ bindings of its links and the dispositions of its paragraphs) and one per
83
+ doc (fields that `al index` can always rebuild). `al` writes every hash and
84
+ every derived field.
85
+ - **Bindings.** When a link is first indexed, `al index` records the hash of
86
+ both ends. Ordinary indexing never moves a binding. When the target
87
+ changes, the source gets a hint until someone checks it and runs
88
+ `al index --align <ID>`.
89
+ - **Consolidation is by hand.** A PR copies a change paragraph into `specs/`
90
+ word for word, and records its disposition: `incorporated`, `removed`,
91
+ `superseded` or `abandoned`. No command writes the spec.
92
+
93
+ ## Paths
94
+
95
+ The user picks the path. The skill has the steps of each path.
96
+
97
+ | Path | When | Records | Sign-off | Closes when |
98
+ |---|---|---|---|---|
99
+ | 0. Fix | no promise changes: it restores what the spec says, or claims a typo in any paragraph | none | no | the PR merges |
100
+ | 1. Small promise amend | one or a few promise paragraphs change | a short request; the PR edits `specs/` directly | yes | the PR merges |
101
+ | 1d. Small design correction | names or wording of design paragraphs only | a short request with a one-line source note; the PR edits `specs/` directly | no | the PR merges |
102
+ | 2. Big change | a real design, one or a few PRs | a request and a change spec | if a promise kind changes | the close rule holds |
103
+ | 3. Epic | big, in parts over time | as 2, with optional task references | as 2 | the close rule holds |
104
+ | S. Spike | not yet clear what to build | a request with an organized question; the findings open with the answer | yes, on the question | the answer names the question version |
105
+
106
+ Every PR states its path and its claim in a commit message, for example
107
+ `Tier: 0 — typo in INV-3` or `Tier: 2 — invoice-payments, part 1`. `al check`
108
+ reads the newest `Tier:` line in the branch's commits, and checks the claim
109
+ against the kinds and the changed paragraphs: "path 0, but a rule paragraph
110
+ is changed with no typo claim" is `not ok`. It checks the labels, not their
111
+ meaning.
112
+
113
+ **The close rule.** `al conclude <name>` refuses while a promise change has
114
+ no sign-off, a spike's current question is not signed, or a change paragraph
115
+ with a baseline effect has no valid disposition for its current version.
62
116
 
63
117
  ## The commands
64
118
 
65
- - `al new <name> --from <file|-> [--tier <1|2|3|S>] [--title <text>]`: start
66
- a request from the owner's words (`-` reads standard input); `--title` sets
67
- its heading, which is the name otherwise.
68
- - `al record <name> origin|signoff|decision|part|section`: write one part of
69
- a record. To change a section the request already holds, write the decision
70
- first, then `al record <name> section <ID> --decision Dn` adds a new version.
71
- - `al context [<name> | <ID> | --diff <range>]`: where the project, a request
72
- or a section stands; `--audit` for the whole trace, `--at <commit>` for any
73
- past state.
74
- - `al spec [--list]`: the design as it stands. `--add-ids <file> --prefix <P>`
75
- gives IDs to the headings of a baseline file that have none.
76
- - `al check [--strict] [--all]`: the hints for this branch, five at most;
77
- `--all` shows every one.
78
- - `al consolidate <name>`: write a request's pending sections into the baseline.
79
- - `al conclude <name>`: write the Outcome (what became of each requirement) and
80
- archive the request.
81
-
82
- Every command that changes files, except `new`, shows what it would write, and
83
- writes only with `--yes`. The skill, `skills/assuredloop/SKILL.md`, says how to
84
- choose a tier (0 to 3, or S for a spike) and when to use which command. The
85
- promises are in `specs/`.
86
-
87
- A request that follows an earlier one says so on its Status line, as in
88
- `Status: open · Follows: <name>`. Every word after `Follows:` is read as a
89
- request name, so write names only.
119
+ - `al new <name> --from <file|-> [--tier <1|1d|2|3|S>] [--title <text>]`:
120
+ start a request from the owner's words (`-` reads standard input).
121
+ - `al record <name> origin --url <source> --from <file|->`: a snapshot of
122
+ later words of the owner, or of a source you rely on.
123
+ - `al record <name> signoff --source <where> --words <their words>`: show what
124
+ the owner signs; with `--yes`, record the sign-off on the owner's own yes.
125
+ - `al record <name> decision --source <who> --text <decision>
126
+ [--clarifies R<n>]`: add D1, D2…
127
+ - `al spec`: every doc's IDs, display numbers and kinds.
128
+ `al spec --add-ids <file> [--prefix <P>]`: give each unmarked paragraph the
129
+ next free ID.
130
+ - `al index`: write the derived facts and the new bindings, and list the AI
131
+ hints to refresh. `al index --align <ID>` moves the bindings of one
132
+ paragraph to its targets' current text, on purpose.
133
+ - `al check [--strict]`: the checks of this branch against its base.
134
+ - `al context [<name> | <ID>]`: where the project, a request or a paragraph
135
+ stands. `--diff <range> --for review` is the review view. `--audit` gives a
136
+ request's whole trace; `--at <commit>` any v4 state.
137
+ - `al conclude <name>`: the close rule; with `--yes` it writes the Outcome
138
+ and moves the request to `requests/archive/<name>/`.
139
+ - `al export [--at <commit>] [--out <file>]`: one JSONL row per paragraph
140
+ version, with its role, version, commit and links. It is not committed.
141
+ - `al search <words>`: see "Search".
142
+
143
+ Every command that changes files, except `new` and `index`, shows what it
144
+ would write, and writes only with `--yes`. Each output ends with three lines:
145
+ `Read` (what it read), `Next` (what to do next) and `Not known` (what the
146
+ tool cannot know).
90
147
 
91
148
  ## Settings
92
149
 
93
- A project may add a file `.assuredloop` at its root, one `key: value` per line,
94
- each path inside the repo:
95
- - `root: <folder>`: the baseline's folder, `specs` when there is no such line;
96
- - `tests: <path>`: a test file or folder beyond the usual names;
97
- - `results: <path>`: a test result file or folder for `al check` to read;
98
- - `adrs: <folder>`: a folder of decision records; `docs/adr` is always read too.
99
-
100
- `tests:`, `results:` and `adrs:` may each be given on several lines.
101
-
102
- ## Common situations
103
-
104
- Each example gives the steps, and what `al check` says on the PR. The `Tier:`
105
- line goes in a commit message and in the PR.
106
-
107
- ### Adopting when the spec lives elsewhere
108
-
109
- Say the design is `docs/prd.md`, and the root is to be `docs/prd/`. Use two
110
- PRs.
111
-
112
- PR 1 moves the file, fixes each relative link the move breaks (`(adr/)`
113
- becomes `(../adr/)`), and sets the root. It comes before the project adopts
114
- AssuredLoop, so it carries no Tier line:
115
-
116
- mkdir docs/prd && git mv docs/prd.md docs/prd/prd.md
117
- printf 'root: docs/prd\n' > .assuredloop
118
-
119
- This is the step before the baseline exists. `al check`, if run on it, exits 0
120
- (`--strict` too) with two notes:
121
-
122
- note: <sha> changes docs/prd/prd.md with no request linked (fine for tier 0; say why); git show <sha>
123
- note: no Tier line in origin/main..HEAD; add "Tier: <n> — <claim>" to a commit message, e.g. with git commit --amend
124
-
125
- A tier-0 claim here would get
126
- `not ok: the claim is tier 0, but origin/main..HEAD edits the baseline`: the
127
- fork had no baseline, so the whole file reads as new.
128
-
129
- PR 2, after PR 1 merges, adopts: the AGENTS.md line from Install, and IDs. It
130
- claims `Tier: 0 — adds section IDs; no promise changes`:
131
-
132
- al spec --add-ids docs/prd/prd.md --prefix PRD --yes
133
-
134
- `al check --strict` passes, with one note: the commit changes
135
- `docs/prd/prd.md` with no request linked (fine for tier 0; say why). In one PR,
136
- the IDs read as edits too: `edits the baseline: [PRD-1], [PRD-2], [PRD-3]`.
137
-
138
- ### Adding IDs to a spec file in the root
150
+ `.assuredloop/config.yaml`, at the repo's root. Every key is optional.
139
151
 
140
- al spec --add-ids specs/api.md --prefix API --yes
141
-
142
- It numbers the headings that have no ID, with the next free numbers. Claim
143
- tier 0. `al check --strict` passes, with the same note.
144
-
145
- ### Moving or splitting sections in the root
146
-
147
- Move each section whole, heading and text unchanged, to another file in the
148
- root. Claim tier 0. `al check --strict` passes, and its Evidence line says
149
- `moves [R-3] specs/rules.md → specs/dates.md, text unchanged`. A new file holds
150
- only the moved sections: a title or an intro line in it is new text, and gets
151
- a `not ok`.
152
-
153
- ### A move that forces a text change
154
-
155
- Moving `[R-2]` from `specs/` into `specs/files/` breaks its link
156
- `(limits.md)`. The fix, `(../limits.md)`, changes the section's text. So does a
157
- heading reworded on the way. `al` follows neither. Claimed as tier 0:
158
-
159
- not ok: the claim is tier 0, but origin/main..HEAD edits the baseline: [R-2]; al context --diff origin/main..HEAD
160
-
161
- Either keep the change out of the move: move the section where its text still
162
- works (a file in the same folder keeps its links), and reword in a tier-1 PR of
163
- its own. Or claim tier 1 for the whole PR, as in the skill's quick path, with
164
- `Amends: [R-2]` and the owner's sign-off. `al check --strict` then passes.
165
-
166
- ### Renaming a section's ID
167
-
168
- Code, tests and requests cite a section by its ID. Rename `[R-2]` to
169
- `[SIZE-1]`, claim tier 0, and `al check` says
170
- `not ok: the claim is tier 0, but origin/main..HEAD edits the baseline: [R-2], [SIZE-1]`.
171
- `al context R-2` then says `[R-2] not in the baseline`, and still lists the
172
- code and tests that name it.
173
-
174
- Keep the ID: it names the promise, not the file it sits in. If it must change,
175
- claim tier 1, with the owner's sign-off and `Amends: [R-2], [SIZE-1]` (name
176
- both, or a note says the new one is not named). In the same PR, change the
177
- citations in code and tests; `al context R-2` lists them. `[R-2]` is never used
178
- again.
179
-
180
- Do not replace `[R-2]` across the whole repo:
181
- - Archived requests and the other append-only records ([REC-12]) stay as they
182
- are, and keep `[R-2]` as history. Editing one gives
183
- `not ok: <sha> requests/archive/<name>/request.md: changes a request archived on main ([REC-12])`.
184
- - An open request that holds `[R-2]` then reads it as
185
- `not found; candidates SIZE-1`, shown as that request's own information. It
186
- is re-aligned in that request's own work. A replace there edits its signed
187
- `origin/` snapshot, which gives a `not ok`.
188
-
189
- ### Starting a new repo from an already-agreed spec
190
-
191
- Adopt the agreed text as it is, with no request: the owner signs a request's
192
- organized requirement, never the spec text ([REC-5]). Say in the commit
193
- message where and when the owner agreed it. Use two steps, as in the first
194
- example.
152
+ ```yaml
153
+ root: specs # the spec folder; every *.md in it except adr/ is a spec doc
154
+ docs: # each file and its ID prefix; other files may be listed too
155
+ - {file: specs/invoices.md, prefix: INV}
156
+ results: .assuredloop/results # where result files are
157
+ outputs: # in the central repo: its output repos
158
+ - {name: invoicer-web, path: ../invoicer-web, commit: <sha>}
159
+ central: {path: ../invoicer} # in an output repo: the central repo
160
+ ```
195
161
 
196
- PR 1, before adoption, imports the agreed text under `specs/` (with
197
- `.assuredloop` if the root is elsewhere). It has no AGENTS.md line and no Tier
198
- line: AssuredLoop is not adopted yet, and its rules start at adoption.
199
- `al check`, if run on it, exits 0 with the two notes PR 1 above gets. In an
200
- empty repo, PR 1 can instead be the first commit, straight to main.
162
+ `.assuredloop/schema.yaml` holds the kinds and the link words, with a version.
163
+ `al spec --add-ids` writes both files when they are absent.
201
164
 
202
- PR 2 adopts: the AGENTS.md line from Install, and the IDs. It claims
203
- `Tier: 0 — adds section IDs and the AGENTS line; no promise changes`:
165
+ ADRs are `specs/adr/NNNN-<slug>.md`, with `Status: proposed`, `accepted` or
166
+ `superseded` on the first line. The heading's marker holds `ADR-<n>` and its
167
+ `decides:`, `source:` and `supersedes:` links. The text of an accepted ADR
168
+ does not change; a new ADR supersedes it.
204
169
 
205
- al spec --add-ids specs/<file>.md --prefix <P> --yes
170
+ ## Search
206
171
 
207
- `al check --strict` passes, with one note: the commit changes
208
- `specs/<file>.md` with no request linked (fine for tier 0; say why). Requests,
209
- with the owner's sign-off, start at the first promise change after that.
172
+ `al search` answers at the strongest level that is installed, falls back by
173
+ itself (2, then 1, then 0), and says which level answered and why.
210
174
 
211
- `specs/` holds promises, and each change to one needs the owner's sign-off, so
212
- a build or UI design belongs in `docs/`, or as ADRs in `docs/adr/`, which `al`
213
- reads, unless a passage is a promise the owner wants guarded.
175
+ | Level | What it is | Needs |
176
+ |---|---|---|
177
+ | 0 | a scan of the export | nothing |
178
+ | 1 | a local full-text index (SQLite FTS5, BM25), with the ID in its own exact column | Node 24 or newer (`node:sqlite`) |
179
+ | 2 | level 1, plus a small local embedding model; word and vector results are fused | the package `@assuredloop/search` |
180
+
181
+ - The default query is the current system: the spec text at the selected
182
+ commit. `--change <name>` adds that request's open change spec, its
183
+ sources and its evidence. `--history` adds removed, abandoned and replaced
184
+ text, marked as history.
185
+ - `--id <ID>` finds one paragraph by its exact ID, never through search.
186
+ `--level <0|1|2>` asks for a lower level; `--at <commit>` another commit.
187
+ - Each hit shows its role (`baseline`, `proposal`, `spike`, `source`,
188
+ `evidence` or `history`), its version and its commit.
189
+ - In the central repo, search covers the output repos that its committed
190
+ config lists, each at its resolved commit. The `Repos` line names each repo
191
+ and its commit, for example
192
+ `Repos invoicer@a6ac3a7785dd invoicer-web@5aa04042117b`. An output repo
193
+ gives `evidence` rows: its result files, and the files that cite a central
194
+ ID or that a record declares. Such a hit shows `<repo>:<path>`, and each
195
+ line that names a central ID, with its line number. A repo that is absent,
196
+ or a commit that cannot be found, gives no rows and a `Not known` line with
197
+ the reason.
198
+ - The index is one SQLite file inside `.git`, never committed. `al search`
199
+ brings it up to date before it answers; `--rebuild` builds it again.
200
+ - Level 2 runs a small local model (bge-small-en-v1.5, pinned by its
201
+ revision). The model download is the only data that leaves the machine.
202
+ `al` itself makes no network call.
203
+
204
+ ## One central repo, and output repos
205
+
206
+ The central repo holds `specs/`, the ADRs, the requests and the records. Its
207
+ config lists the output repos. An output repo holds code, tests and user
208
+ documents only; its config names the central repo.
209
+
210
+ - Code and tests in an output repo cite central IDs with a qualifier:
211
+ `central:INV-41`, `central:invoice-exports/R3`. A fix there says
212
+ `Tier: 0 — restores central:INV-41`.
213
+ - `al` reads another repo only through git, at the commit that config pins
214
+ or at the clone's HEAD, and never fetches. A repo or a commit that is not
215
+ there is "unknown", never a guess.
216
+ - In an output repo, `al check` looks up the central IDs that the branch's
217
+ changed files cite.
218
+
219
+ ## Adopting AssuredLoop
220
+
221
+ 1. Put the spec under the root (`specs/` by default), or set `root:`.
222
+ 2. Mark every paragraph: `al spec --add-ids specs/<file>.md --prefix <P> --yes`
223
+ for each spec file. Headings get the kind `note`. Write the kind of each
224
+ other paragraph into its marker. An adopted paragraph needs no link.
225
+ 3. Add the AGENTS.md line from "Install". Claim
226
+ `Tier: 0 — adds paragraph IDs; no promise changes`.
227
+ 4. `al spec --add-ids --yes` also records where the adopted text came from.
228
+ For each paragraph it marks whose text is a block of the file at HEAD, in
229
+ the same place, it writes an entry with HEAD's commit and the text's hash
230
+ to `.assuredloop/records/requests/adoption.yaml`. It writes
231
+ `requests/archive/adoption/request.md` when that file is absent. So commit
232
+ the spec unmarked before you mark it. A paragraph whose text is not at
233
+ HEAD is not adopted: the command names it, and it follows its path as a
234
+ change. `source: adoption` says where the text came from. It is not an
235
+ owner approval, and it does not excuse a later change.
236
+ 5. Run `al index`, and commit the markers and the records together. On that
237
+ branch, `al check --strict` reads the adopted paragraphs as unchanged, so
238
+ they need no sign-off and no path claim.
239
+
240
+ **A sign-off bound to the whole text.** Markers change a file's bytes. If a
241
+ signed requirement, or any other record, binds the whole text of a spec file
242
+ by its SHA-256, that hash no longer matches after the markers are added. Ask
243
+ the owner for a new approval after the conversion. The paragraph text itself
244
+ does not change; `al` hashes each paragraph without its marker.
245
+
246
+ **From 0.1.0.** v4 (0.2.0) does not read 0.1.0 records. Keep 0.1.0 pinned
247
+ until you move. Older records stay readable as files; run the pinned 0.1.0 at
248
+ those commits. To move:
249
+
250
+ 1. Finish each open 0.1.0 request on its pinned copy, or start it again
251
+ under v4.
252
+ 2. Install 0.2.0 (see "Install").
253
+ 3. Run `al spec --add-ids`, as in steps 1-5 above. It marks every paragraph
254
+ and writes the adoption record.
214
255
 
215
256
  ## What is enforced, and by whom
216
257
 
217
- The way of working (tests first, review, the PR flow) belongs to the bots that
218
- use AssuredLoop, and is not in this table.
219
-
220
258
  | The tool checks | The skill asks | The owner decides |
221
259
  |---|---|---|
222
- | `consolidate` and `conclude` refuse while the requirement is not signed, or a section is not ready | write the owner's words and the organized requirement, and ask for the sign-off | what is wanted, by signing the organized requirement |
223
- | section states: was and now against the baseline, by exact text | choose the tier, and state it in a commit message (where `al check` reads it) and the PR | whether a changed requirement is signed again |
224
- | append-only records, snapshot hashes, duplicate IDs, broken links, as hints | read the hints, and fix each `not ok` or say why it stands | decisions whose source is the owner, such as dropping or keeping work |
225
- | `check --strict` exits 1 on a `not ok` this branch owns, when a project opts in | record each later decision, with its source | |
226
-
227
- Everything else the tool shows is a hint: an observation, not a guarantee.
228
- Nothing is installed in git hooks.
229
-
230
- ## Beyond code
231
-
232
- The same records work on a repo of documents alone. The documents are the
233
- deliverable, and `specs/` holds promises about them. "Tests" are named checks
234
- (a deterministic check, a checklist or a review), listed with `tests:` in
235
- `.assuredloop`; their results are the files they write, listed with
236
- `results:`, in TAP or JUnit form. A result counts as evidence for a change
237
- only when a `revision: <sha>` line names the commit being checked:
238
- `# revision: <sha>` in TAP, `<!-- revision: <sha> -->` in JUnit XML. A result
239
- with no such line, or at an older commit, is shown but is not evidence.
240
- `test/non-code.test.js` walks one through.
260
+ | `al conclude` refuses on its three conditions (see "The close rule") | write the owner's words and the organized requirement, and ask for the sign-off | what is wanted, by signing the organized requirement |
261
+ | IDs: missing, used twice, lost, used again; kinds and links; links that do not resolve; sign-off coverage of promise changes; path and typo claims; dispositions and exact equality; stale bindings; overlapping changes; ADR text changes; result applicability, as hints | choose the path, and state it in a commit message and the PR | whether a changed requirement is signed again |
262
+ | `check --strict` exits 1 on a `not ok`, when a project opts in | record each later decision, with its source | decisions whose source is the owner, such as dropping or keeping work |
263
+
264
+ `al` checks that declarations are well formed and that references resolve.
265
+ It does not check that a kind is right, that a requirement is fully
266
+ covered, that a test checks the rule it names, or that a change is
267
+ authorized in substance; its views say "not checked" for these. Nothing is
268
+ installed in git hooks.
269
+
270
+ ## Beyond code: results
271
+
272
+ A result file in `.assuredloop/results/` (or the `results:` folder) records a
273
+ check, a test run or a review:
274
+
275
+ ```yaml
276
+ check: test/export-link.test.js
277
+ outcome: pass # pass, fail or not run
278
+ commit: <sha> # or unknown
279
+ inputs:
280
+ - {file: src/export-link.js, sha256: <sha256 of its bytes>}
281
+ by: ci # optional, with source and note
282
+ ```
283
+
284
+ `al` shows "declared inputs unchanged since <commit>" when the inputs still
285
+ have those hashes, "does not apply to the current text" when one changed,
286
+ and "applicability unknown" when it cannot tell. That the declared inputs
287
+ are complete is a claim. The same works for a repo of documents: the report
288
+ is the deliverable, and a review result names it as its input.
241
289
 
242
290
  ## This repository
243
291
 
@@ -251,11 +299,15 @@ in this repository.
251
299
 
252
300
  ## Releasing
253
301
 
254
- 1. Bump `version` in `package.json` in a PR, and merge it.
302
+ 1. Bump `version` in `package.json` and in `packages/search/package.json` to
303
+ the same version in a PR, and merge it.
255
304
  2. Publish a GitHub Release tagged `v<version>` on that commit. Mark it a
256
305
  pre-release to publish under npm's `next` tag.
257
306
 
258
307
  `.github/workflows/publish.yml` does the rest: it runs the tests and
259
- `al check --strict`, checks that the tag matches `package.json`, and publishes
260
- @assuredloop/cli to npm. It stores no npm token: npm trusts the workflow by
261
- name, and adds a provenance statement saying which commit built the package.
308
+ `al check --strict`, checks that the tag matches both `package.json` files,
309
+ and publishes @assuredloop/cli, then @assuredloop/search, to npm. It skips a
310
+ package whose version is already on npm, so a failed run can run again. It
311
+ stores no npm token: npm trusts the workflow by name, and adds a provenance
312
+ statement saying which commit built the package. npm must trust the workflow
313
+ for each package before its first publish.