@lumoai/cli 1.58.0 → 1.60.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/assets/skill/SKILL.md +15 -17
- package/assets/skill/references/artifacts-figma.md +4 -3
- package/assets/skill/references/confirmation.md +133 -0
- package/assets/skill/references/criteria.md +12 -21
- package/assets/skill/references/doc-editing.md +11 -9
- package/assets/skill/references/docs.md +4 -3
- package/assets/skill/references/memory.md +4 -2
- package/assets/skill/references/milestones.md +3 -2
- package/assets/skill/references/outcome.md +1 -14
- package/assets/skill/references/plan-runs.md +5 -0
- package/assets/skill/references/sessions.md +4 -4
- package/assets/skill/references/sprints.md +18 -17
- package/assets/skill/references/task-deps.md +4 -3
- package/assets/skill/references/tasks.md +34 -2
- package/assets/skill/references/verify.md +71 -71
- package/assets/skill/references/worktree.md +13 -7
- package/dist/cli/src/commands/crossing-disposition.js +342 -0
- package/dist/cli/src/commands/crossing-explain.js +10 -21
- package/dist/cli/src/commands/doc-delete.js +35 -23
- package/dist/cli/src/commands/doc-rebuild-source.js +16 -4
- package/dist/cli/src/commands/memory-rm.js +68 -10
- package/dist/cli/src/commands/milestone-delete.js +13 -10
- package/dist/cli/src/commands/outcome.js +0 -77
- package/dist/cli/src/commands/session-attach.js +8 -2
- package/dist/cli/src/commands/sprint-close.js +29 -9
- package/dist/cli/src/commands/sprint-delete.js +13 -10
- package/dist/cli/src/commands/sprint-show.js +3 -9
- package/dist/cli/src/commands/task-artifact-rm.js +58 -28
- package/dist/cli/src/commands/task-criteria-list.js +1 -4
- package/dist/cli/src/commands/task-criteria-set.js +3 -12
- package/dist/cli/src/commands/task-deps.js +20 -6
- package/dist/cli/src/commands/task-status.js +196 -111
- package/dist/cli/src/commands/task-update.js +129 -0
- package/dist/cli/src/commands/verify.js +22 -13
- package/dist/cli/src/commands/worktree-rm.js +35 -7
- package/dist/cli/src/index.js +60 -48
- package/dist/cli/src/lib/blocked-error.js +183 -0
- package/dist/cli/src/lib/bound-task.js +32 -0
- package/dist/cli/src/lib/confirmation.js +119 -0
- package/dist/cli/src/lib/hook-runner.js +23 -11
- package/dist/cli/src/lib/open-crossings.js +6 -6
- package/dist/shared/src/referent-kind.js +31 -1
- package/dist/shared/src/security-scan.js +125 -0
- package/package.json +1 -1
- package/assets/skill/references/fidelity.md +0 -32
- package/dist/cli/src/commands/fidelity.js +0 -108
- package/dist/cli/src/commands/verdict.js +0 -189
package/assets/skill/SKILL.md
CHANGED
|
@@ -34,8 +34,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
34
34
|
| `task criteria set/list`, drafting the acceptance contract | [references/criteria.md](references/criteria.md) |
|
|
35
35
|
| `verify`, `task status` — machine verification loop, claim-done flow, self-check/resume | [references/verify.md](references/verify.md) |
|
|
36
36
|
| `cost` — per-operation (per-tool) token cost read-out; `task lineage` Top-5 | [references/task-context.md](references/task-context.md) |
|
|
37
|
-
| `outcome show/
|
|
38
|
-
| `fidelity show` — per-delivery grounding + independence change-pattern read-out | [references/fidelity.md](references/fidelity.md) |
|
|
37
|
+
| `outcome show/rate` — post-hoc outcome well (falsifier oracle, rejection-only) | [references/outcome.md](references/outcome.md) |
|
|
39
38
|
| `priority [text]`, `priority list` — team priority declaration (append-only) | [references/priority.md](references/priority.md) |
|
|
40
39
|
| `project list`, `milestone*` | [references/milestones.md](references/milestones.md) |
|
|
41
40
|
| `doc create/update/list/move/bind/share/import` (CRUD) | [references/docs.md](references/docs.md) |
|
|
@@ -44,6 +43,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
44
43
|
| `task/project memory`, `memory promote/rm` | [references/memory.md](references/memory.md) |
|
|
45
44
|
| `session attach/status`, git-suggest on start, Layer-2 review | [references/sessions.md](references/sessions.md) |
|
|
46
45
|
| `worktree add/rm/list` (local dev tooling) | [references/worktree.md](references/worktree.md) |
|
|
46
|
+
| `--confirm` / exit code 4 — the confirmation envelope every gated mutation speaks | [references/confirmation.md](references/confirmation.md) |
|
|
47
47
|
|
|
48
48
|
## Command catalog
|
|
49
49
|
|
|
@@ -67,7 +67,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
67
67
|
### Tasks — see [tasks.md](references/tasks.md)
|
|
68
68
|
|
|
69
69
|
- `lumo task create <title> [flags]` — create a task. **Mid-task** (your session is bound to an in-flight task) it requires `--rework-of <id>` (redirects you to fix the existing task — creates nothing) or `--new-scope` (genuinely new, out-of-scope work). On a send-back, fix in place / amend the contract instead of spinning off a new task — see [verify.md](references/verify.md) and [criteria.md](references/criteria.md).
|
|
70
|
-
- `lumo task update <id> [flags]` — patch status/title/priority/assignee/milestone/sprint/tags; `--claimable`/`--not-claimable` set the agent-claimable marker (LUM-646)
|
|
70
|
+
- `lumo task update <id> [flags]` — patch status/title/priority/assignee/milestone/sprint/tags; `--claimable`/`--not-claimable` set the agent-claimable marker (LUM-646). `--status done` without `--confirm` exits 4 with a confirmation envelope (see [confirmation.md](references/confirmation.md))
|
|
71
71
|
- `lumo task list [flags]` — list tasks assigned to you
|
|
72
72
|
- `lumo next [--count N] [--claimable]` — recommend the next task to work on (read-only). `--claimable` restricts to the autonomy boundary: only tasks that are claimable ∩ unblocked (F3 topology) ∩ within milestone budget (F2); old server degrades gracefully to the standard ranking (LUM-646)
|
|
73
73
|
- `lumo task show <id>` — print one task's detail
|
|
@@ -97,7 +97,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
97
97
|
- `lumo task deps add <id> --blocked-by <LUM-N>` — declare a manual hard dependency (CONFIRMED)
|
|
98
98
|
- `lumo task deps confirm <id> <edge> [--reverse]` — confirm a detected candidate (`--reverse` flips direction)
|
|
99
99
|
- `lumo task deps dismiss <id> <edge>` — dismiss a candidate (never re-suggested)
|
|
100
|
-
- `lumo task deps rm <id> <edge> --
|
|
100
|
+
- `lumo task deps rm <id> <edge> --confirm` — delete an edge (without `--confirm`: exit 4 + confirmation envelope; `--yes` is a legacy alias)
|
|
101
101
|
- `<edge>` = short edge-id prefix (≥6 chars) or the other task's identifier; ambiguous/unknown selectors list candidates and exit 1. See [tasks.md](references/tasks.md)
|
|
102
102
|
|
|
103
103
|
### Acceptance criteria (contract) — see [criteria.md](references/criteria.md)
|
|
@@ -107,10 +107,10 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
107
107
|
|
|
108
108
|
### Verification (machine acceptance loop) — see [verify.md](references/verify.md)
|
|
109
109
|
|
|
110
|
-
- `lumo verify [task] --note "<self-report>" [--timeout <seconds>]` — run every MACHINE criterion's checkpointer locally and report a structured PASS/FAIL verdict per criterion.
|
|
111
|
-
- `lumo task status [task] [--json]` — read-only acceptance self-check (no LLM): the contract with each criterion's latest verdict,
|
|
112
|
-
- `lumo
|
|
113
|
-
- `lumo crossing
|
|
110
|
+
- `lumo verify [task] [--note "<self-report>"] [--timeout <seconds>]` — run every MACHINE criterion's checkpointer locally and report a structured PASS/FAIL verdict per criterion. `--note` is an optional one-line self-report ("我改了 X,因为 Y 可验收"), frozen as the task's claim (source AGENT) when the round passes into IN_REVIEW. The round cap is the workspace's `verificationMaxRounds` (default 3) — read the actual budget off the `Round N/M` line the command prints, never assume a number. All-pass → task to IN_REVIEW (agent stops); a fail on the last round → escalate to human. **Run this before claiming a task is done.**
|
|
111
|
+
- `lumo task status [task] [--full] [--json]` — read-only acceptance self-check (no LLM): the contract with each criterion's latest verdict, the current round, last failure reasons, `nextActions` (the unmet criteria, plus any undispositioned PR **security findings** as `SECURITY_FINDING` entries — `blocks DONE` vs `advisory`), a per-linked-PR **scan status line** (stage states incl. the L3 `hunt` layer, external-finding count, partial flag, external failure reason — LUM-735/739) plus the hunt's per-category coverage line (LUM-762), and any OPEN boundary crossings; `--full` adds the dashboard sections (verification rollup, history, cost, struggle trail, trend) (fails closed — `null`/`⚠` means "could not confirm", not safe). **Run it first when resuming a task or after a round was rejected.**
|
|
112
|
+
- `lumo crossing explain <id> --note "<text>"` — append an agent self-explanation ("申辩") to a boundary crossing; append-only, **never clears the crossing or unblocks Done**. A review aid, not a self-clear.
|
|
113
|
+
- `lumo crossing disposition <id> --false-positive | --confirmed [--note "<text>"] [--task <LUM-N>]` — record the **user's** ruling on a task crossing through a **three-step** confirmation handshake the server enforces (LUM-769): (1) no step flag — prints the crossing (severity, detail, recurrence, your explanations) as an exit-4 envelope with a stage-1 **read receipt**, writes nothing; relay it and ask the user to confirm they have **read** it, then run its `confirmCommand` (`--receipt <r1> --confirm-read`); (2) that prints a second exit-4 envelope for the ruling with the stage-2 receipt; relay it and ask the user to **approve**, then run its `confirmCommand` (`--receipt <r2> --confirm`); (3) the write. Confirming the ruling before the read is acknowledged is refused and told to confirm the read first; never supply either step flag yourself. Either ruling clears that crossing's block on DONE and is audited as a CLI-channel disposition. Reverting to OPEN, repository suppression rules and steward (milestone) crossings stay web-only. See [verify.md](references/verify.md)
|
|
114
114
|
|
|
115
115
|
### Cost (per-operation token read-out) — see [task-context.md](references/task-context.md)
|
|
116
116
|
|
|
@@ -128,13 +128,8 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
128
128
|
### Outcome well (post-hoc oracle) — see [outcome.md](references/outcome.md)
|
|
129
129
|
|
|
130
130
|
- `lumo outcome show <task>` — read the post-hoc outcome well: the **falsifier** verdict (`REJECTED` | `INCONCLUSIVE` — never a "pass") plus its backing rejection signals. `INCONCLUSIVE` = no rejection on record, **not** "satisfied".
|
|
131
|
-
- `lumo outcome record <task> --note "<what reality did>" [--kind <kind>]` — record a human-observed post-hoc **rejection** of a delivery (revert / rollback / CI regression / downstream redirect / bypass). Append-only; **there is no "mark satisfied" counterpart** — the well only asserts rejection. `--note` is required (the observed referent).
|
|
132
131
|
- `lumo outcome rate [--min N] [--json]` — workspace **trust × post-hoc-fate** join (LUM-603, LUM-606): per delivery-time **verification-friction** bucket (`no-verification` / `single-round` / `multi-round-or-sendback` — two raw counts frozen at delivery, replacing the saturating forecast-confidence axis), the post-hoc REJECTED rate from the well. Honest by construction — thin buckets read `insufficient` (no fabricated rate), the single-round-vs-multi comparison stays `inconclusive` until CIs separate, and the rate is a **lower bound** (no signal = INCONCLUSIVE, never satisfied). Bucket names are value-neutral — direction is decided by the correlation, never welded into the label. Under-sampled today by design — the skeleton produces real strata once the well fills.
|
|
133
132
|
|
|
134
|
-
### Fidelity read-out (mechanical change-pattern) — see [fidelity.md](references/fidelity.md)
|
|
135
|
-
|
|
136
|
-
- `lumo fidelity show <task> [--json]` — per delivery snapshot (LUM-609), a **composition table, not a single score**: (1) the **grounding** of the frozen contract — grounded (`EXTERNAL_FACT`, a machine-checkable upper bound) / self-confirming (`AGENT_CONSTRUCTED_STATE` + `UNVERIFIED_ASSERTION`) / inconclusive (`PENDING_OUTCOME` + `UNCLASSIFIED`, surfaced not swallowed) + the full effective-kind tally; (2) the **independence** signal — criteria `ADDED`/`UPDATED` at round>0 (after work started) that the delivery rode on = backward-inference suspects. Purely mechanical (timing + op + grounding) — **no direction verdict**. A no-snapshot task is reported explicitly (not a pass). Zero new storage — reads the snapshot + `CRITERION_CHANGED` trail.
|
|
137
|
-
|
|
138
133
|
### Artifacts & Figma — see [artifacts-figma.md](references/artifacts-figma.md)
|
|
139
134
|
|
|
140
135
|
- `lumo task artifact add/update/list/show/rm` — record spec/plan products on a task
|
|
@@ -174,7 +169,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
174
169
|
|
|
175
170
|
- `lumo task memory add/list` · `lumo project memory add/list` — record/curate Memory (TASK vs PROJECT)
|
|
176
171
|
- `lumo memory show <id>` — show one memory's full card (category + content) by id (progressive disclosure from a one-line index entry)
|
|
177
|
-
- `lumo memory promote <id>` / `lumo memory rm <id> --
|
|
172
|
+
- `lumo memory promote <id>` / `lumo memory rm <id> --confirm` — TASK→PROJECT / delete (exit 4 + envelope without `--confirm`)
|
|
178
173
|
- `lumo memory sync [--dry-run] [--clean]` — downsync team memory into the local Claude Code store (`team/<id>.md` + a managed MEMORY.md block); only touches files it owns
|
|
179
174
|
- `lumo memory push [--dry-run]` — upsync locally-authored memories from `<memory-dir>/outbox/*.json` to the team
|
|
180
175
|
- `lumo memory fold [project-ref] --dry-run` — read-only PREVIEW of the autonomous topic-fold pass (folding runs via a daily cron; no manual apply, no `unfold`). See [memory.md](references/memory.md)
|
|
@@ -182,7 +177,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
182
177
|
### Sessions — see [sessions.md](references/sessions.md)
|
|
183
178
|
|
|
184
179
|
- `lumo session attach <id>` — bind this session to a task (then run `task context`). **Lifetime lock**: re-attaching to the same task is a no-op; attaching to a _different_ task is refused with 409 — start a new Claude Code session instead. No `--force`, no `session detach`.
|
|
185
|
-
- `lumo session attach --steward <milestone>` — bind this session to a **milestone** as a **STEWARD (governance) session** (LUM-640): plan & accept only. Governance passes (task create/update, criteria set incl. `--human`, deps confirm/dismiss,
|
|
180
|
+
- `lumo session attach --steward <milestone>` — bind this session to a **milestone** as a **STEWARD (governance) session** (LUM-640): plan & accept only. Governance passes (task create/update, criteria set incl. `--human`, deps confirm/dismiss, milestone add/remove, milestone triage (LUM-646 claimable), all reads); implementation is gated (`lumo verify` → 409 **without burning a round**; moving a task to in_progress assigned to yourself → 409); commits/PRs produced anyway are recorded as milestone-scoped boundary crossings (fail-closed; disposition stays web+human-only, no CLI clear path). Same lifetime lock: same milestone idempotent, any other attach (a task, or a different milestone) → 409; multiple stewards per milestone are fine. See [sessions.md](references/sessions.md)
|
|
186
181
|
- `lumo session status` — show current binding (a task, or the milestone + STEWARD role)
|
|
187
182
|
- End-of-session housekeeping is fully automatic (no command). On DONE the server runs three best-effort silent passes: Layer-1 memory curation, fragment-usage audit, and blocked-tag automation. See [sessions.md](references/sessions.md)
|
|
188
183
|
- Git-suggest at session start (suggests `session attach`, never auto-binds) + Layer-2 project-memory review — see the reference
|
|
@@ -190,7 +185,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
|
|
|
190
185
|
### Worktrees (local dev tooling) — see [worktree.md](references/worktree.md)
|
|
191
186
|
|
|
192
187
|
- `lumo worktree add <LUM-N> [slug]` — scaffold `.worktrees/<LUM-N>` + node_modules symlink off origin/main; run from the main checkout
|
|
193
|
-
- `lumo worktree rm <LUM-N> --
|
|
188
|
+
- `lumo worktree rm <LUM-N> --confirm` — remove a worktree (exit 4 + envelope without `--confirm`; dirty tree also needs `--force`; keeps the branch unless `--delete-branch`)
|
|
194
189
|
- `lumo worktree list` — list `.worktrees/` worktrees (task id, branch, dirty, node_modules link)
|
|
195
190
|
|
|
196
191
|
## Next-step hints (the trailing `Next:` block)
|
|
@@ -207,6 +202,7 @@ The block never replaces the acceptance-contract section: on `session attach` /
|
|
|
207
202
|
|
|
208
203
|
Don't guess these:
|
|
209
204
|
|
|
205
|
+
- No `lumo verdict`, `lumo fidelity`, or `lumo outcome record` (removed in LUM-733): send-backs and passes are human-only in the web verdict bar; outcome signals are derived automatically (git revert feed); the fidelity read-out is an internal API (`GET /api/tasks/<id>/fidelity`), not a CLI command
|
|
210
206
|
- No `lumo session start` — binding is `lumo session attach <LUM-N>`
|
|
211
207
|
- No `lumo session detach` — the session↔task binding is a lifetime lock; to work on a different task, start a new Claude Code session
|
|
212
208
|
- No steward "role switch" or un-steward — `session attach --steward` is the same lifetime lock on a milestone; a steward session never converts to an implementation session (and there is no CLI path to clear its boundary crossings)
|
|
@@ -217,7 +213,8 @@ Don't guess these:
|
|
|
217
213
|
- No `--content` on `task/project memory add` — memory is structured fields (`--category` + per-category flags), see [memory.md](references/memory.md)
|
|
218
214
|
- No global `--verbose` flag on any command
|
|
219
215
|
- `lumo task comments list` (plural) **reads** the thread; `lumo task comment` (singular) **writes** one
|
|
220
|
-
- Status updates: `lumo task update LUM-N --status done` is one direct call — do **not** walk `in_progress → in_review → done` step by step (see [tasks.md](references/tasks.md) for the transition matrix; under the verify flow you shouldn't be setting `in_review`/`done` yourself at all)
|
|
216
|
+
- Status updates: `lumo task update LUM-N --status done` is one direct call — do **not** walk `in_progress → in_review → done` step by step (see [tasks.md](references/tasks.md) for the transition matrix; under the verify flow you shouldn't be setting `in_review`/`done` yourself at all). `--status done` has no interactive prompt and no `--yes`: without `--confirm` it exits 4 with a confirmation envelope you relay to the user (see [confirmation.md](references/confirmation.md))
|
|
217
|
+
- No interactive yes/no prompts anywhere, and no `--yes` on `task update` — every gated mutation exits 4 with a `confirmation_required` envelope instead; `--yes` survives only as a legacy alias of `--confirm` on the delete/rm/close commands
|
|
221
218
|
|
|
222
219
|
## Core workflow
|
|
223
220
|
|
|
@@ -239,4 +236,5 @@ Don't guess these:
|
|
|
239
236
|
- **Evidence before "done".** Never claim done from reading code — run `lumo verify`. While a PR is open, the task is IN_REVIEW, not DONE.
|
|
240
237
|
- **Never set DONE yourself after a verify loop** — that adjudication is human-only. An unresolved send-back blocks the DONE transition with 409.
|
|
241
238
|
- **Status updates are one direct call** (`task update --status done`), not a step-by-step walk through `in_progress → in_review → done`.
|
|
239
|
+
- **Exit code 4 = the user must confirm — you may not.** A gated mutation (`--status done`, `sprint/milestone/doc delete`, `memory rm`, `task deps/artifact rm`, `sprint close --move-all/--backlog-all`, `worktree rm`, `doc rebuild-source` on an existing source) run without `--confirm` prints a `confirmation_required` envelope on stdout and does nothing. Show every line of its `changes` to the user, wait for their explicit approval, then run its `confirmCommand` verbatim. **Never add `--confirm` (or `--yes` / `--force`) yourself** — the flag means "the user has confirmed", and adding it on your own initiative is the exact failure the protocol exists to stop. **Exit code 5 = blocked by a human-only gate** (`DONE_BLOCKED`: a send-back, an undispositioned boundary crossing, a blocking security finding): relay its `blockers` and `remediation` to the user; nothing on `task update` clears it — no retry, no flag, no rewording a failed criterion. A boundary crossing is the one blocker with a terminal path, and it is the user's: `lumo crossing disposition <id> --false-positive | --confirmed` prints an exit-4 envelope you relay exactly like `--status done` — never self-approve. Details: [confirmation.md](references/confirmation.md)
|
|
242
240
|
- **Read the reference before composing a command** whose flags/edge-cases matter — don't run from memory.
|
|
@@ -46,12 +46,13 @@ Prints one artifact's key:value header (id, kind, title, agent, source, order, t
|
|
|
46
46
|
lumo task artifact show LUM-42 cma_xxx
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
#### `lumo task artifact rm <task> <artifact-id> --
|
|
49
|
+
#### `lumo task artifact rm <task> <artifact-id> --confirm`
|
|
50
50
|
|
|
51
|
-
Deletes an artifact from a task. Irreversible
|
|
51
|
+
Deletes an artifact from a task. Irreversible. Without `--confirm` the CLI fetches the artifact and exits **4** with a confirmation envelope naming it (`Will delete artifact cma_xxx "API spec" (SPEC) from LUM-42` · `Artifact deletion is irreversible`) — no DELETE is sent; relay `changes` to the user and re-run `confirmCommand` on approval ([confirmation.md](confirmation.md)). `--yes` is a legacy alias. On success prints `Removed <artifact-id> from <task>`. A 404 (task or artifact missing in this workspace) prints the server message and exits 1.
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
lumo task artifact rm LUM-42 cma_xxx
|
|
54
|
+
lumo task artifact rm LUM-42 cma_xxx # exit 4 + envelope
|
|
55
|
+
lumo task artifact rm LUM-42 cma_xxx --confirm # after the user approved
|
|
55
56
|
```
|
|
56
57
|
|
|
57
58
|
When to suggest: after running a spec/plan workflow in Claude Code, offer to record the product(s) with `task artifact add` (one call per artifact) — always pass `--source` with the framework you used. Use `task artifact list` to see what's already recorded, `task artifact show` to inspect a single artifact's content, `task artifact update` to fix a wrong kind/title/source without re-uploading, and `task artifact rm` to drop one that's wrong or stale.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Confirmation protocol (`--confirm`, exit code 4)
|
|
2
|
+
|
|
3
|
+
Some `lumo` commands change or destroy state that a human should sign off on first — deleting a sprint, milestone, document, memory, artifact or dependency edge; closing a sprint with unfinished tasks; removing a worktree; re-deriving a doc's markdown source; and moving a task to **DONE**. Since LUM-755 they all speak one protocol instead of prompting or hard-refusing:
|
|
4
|
+
|
|
5
|
+
1. You run the command **without `--confirm`**.
|
|
6
|
+
2. The CLI computes, from real server/local state, what it would do — and **does not do it**. It prints a **confirmation envelope on stdout** and exits **4**.
|
|
7
|
+
3. You show the envelope's `changes` to the user, verbatim.
|
|
8
|
+
4. The user approves or rejects.
|
|
9
|
+
5. Only on approval, you re-run the envelope's `confirmCommand` — the same invocation with `--confirm` appended.
|
|
10
|
+
|
|
11
|
+
There is no interactive yes/no prompt on a TTY either: a human and an agent walk the same steps.
|
|
12
|
+
|
|
13
|
+
## The envelope
|
|
14
|
+
|
|
15
|
+
When stdout is not a TTY (the agent path) the envelope is JSON:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"status": "confirmation_required",
|
|
20
|
+
"command": "sprint delete",
|
|
21
|
+
"changes": [
|
|
22
|
+
"Will delete sprint #3 \"Sprint 3\"",
|
|
23
|
+
"12 tasks under it keep their data; only sprintId is cleared"
|
|
24
|
+
],
|
|
25
|
+
"confirmCommand": "lumo sprint delete 3 --confirm"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Field | Meaning |
|
|
30
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| `status` | Always `confirmation_required`. |
|
|
32
|
+
| `command` | The command path, e.g. `task update`, `worktree rm`. |
|
|
33
|
+
| `changes` | Human-readable lines describing exactly what would happen, computed from the current state (titles, counts, linked PRs, dirty files…). Never empty. |
|
|
34
|
+
| `confirmCommand` | Your original argv (flags and quoting preserved) plus `--confirm` — and, when a second gate applies, that gate's flag too (`--force --confirm`). |
|
|
35
|
+
|
|
36
|
+
On a TTY the same fields are rendered as text: a header line, one `-` bullet per change, then `Re-run with --confirm once the user has approved:` and the command on its own line.
|
|
37
|
+
|
|
38
|
+
Nothing goes to stderr; the envelope is the command's result, not an error. **Exit 4 is the only signal you need** — do not grep the text to decide whether a command "wants confirmation".
|
|
39
|
+
|
|
40
|
+
## Rules for an agent
|
|
41
|
+
|
|
42
|
+
- **Exit 4 → stop and relay.** Print every line of `changes` to the user. Do not paraphrase away a `⚠` line.
|
|
43
|
+
- **Wait for an explicit approval.** A user who asked you to "delete the sprint" earlier has not yet seen what the envelope says will happen; the envelope is what they approve.
|
|
44
|
+
- **Run `confirmCommand` unchanged.** Do not rebuild the command by hand, do not drop flags the envelope carried (`--force`, `--team`, `--project`…).
|
|
45
|
+
- **Never add `--confirm` (or `--yes`, or `--force`) on your own initiative.** `--confirm` means "the user has confirmed". Passing it without that approval is the one thing this protocol exists to prevent, and it is visible in the session trail.
|
|
46
|
+
- A rejected envelope is not an error to retry — report the user's decision and move on.
|
|
47
|
+
|
|
48
|
+
## Flags
|
|
49
|
+
|
|
50
|
+
- `--confirm` — the user approved. Present on every command in the table below.
|
|
51
|
+
- `--yes` — legacy alias of `--confirm` on the commands that took it before LUM-755. Prefer `--confirm` in new invocations. `task update` never had `--yes` and does not gain it.
|
|
52
|
+
- `--force` — a **second gate** that stays separate from `--confirm`: `worktree rm` uses it to acknowledge discarding uncommitted changes; `doc rebuild-source` uses it to acknowledge replacing an existing source. Missing `--force` also yields an envelope (exit 4) whose `confirmCommand` carries `--force --confirm`.
|
|
53
|
+
- `--confirm-read` + `--receipt <token>` — the **read-acknowledgement handshake** (LUM-769) on `crossing disposition`, a three-step protocol the _server_ enforces, the way a web form is loaded, "I have read this" is ticked, and only then submit works. **Step 1** (no step flag) reads the crossing and obtains a stage-1 receipt bound to the crossing, the ruling, your session/member and the crossing's current state (ruling, recurrence, explanations); its envelope's `confirmCommand` carries `--receipt <r1> --confirm-read`. **Step 2** (`--confirm-read`, after the user says they have read it) has the server verify r1 and return the stage-2 receipt; the CLI prints a second envelope for the ruling whose `confirmCommand` carries `--receipt <r2> --confirm`. **Step 3** (`--confirm`, after the user approves the ruling) writes. Confirming the ruling with the stage-1 receipt is refused — locally before any request, and by the server with 409 — and told to confirm the read first; a receipt that is missing, forged, expired (10-minute TTL), for another reader/ruling, or older than the crossing's latest change (a recurrence, a new explanation, a ruling) is refused too, nothing written — re-run without a step flag for a fresh envelope. Each envelope lists its receipt under `receipt: { token, expiresAt }`. The audit row records shown / read-acknowledged / confirmed times. This makes the order un-skippable; it does not, and cannot, prove the user personally ticked the box — you relay each step — so the ruling is recorded as a CLI-channel disposition.
|
|
54
|
+
|
|
55
|
+
## Commands that use the protocol
|
|
56
|
+
|
|
57
|
+
| Command | `changes` describes | Notes |
|
|
58
|
+
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| `task update <id> --status done` | `Will move LUM-N "title" to DONE` · `Status: <current> → DONE` · one line per linked PR (`#926 merged title url`) or `Pull requests: none linked` · a trailing `⚠ N linked pull request(s) not merged: …` when any PR is open/closed/draft | Only `--status done` is gated; other statuses PATCH directly. The server's own DONE gates (unresolved send-back, open boundary crossing → 409) still apply after `--confirm`. See [tasks.md](tasks.md). |
|
|
60
|
+
| `crossing disposition <id> --false-positive` / `--confirmed` | **Envelope 1 (read):** `Will disposition crossing <id> on LUM-N as FALSE_POSITIVE` · `Disposition: OPEN → FALSE_POSITIVE` · `[SEVERITY] CATEGORY — detail` · `Seen ×N while open` when it recurred · every agent explanation (`agent self-report · unverified`) or `Agent explanations: none recorded` · `Note to record: …` · `⚠ Approving clears this crossing's block on moving LUM-N to DONE` (or `Advisory crossing — it never blocked DONE…`) · `⚠ HIGH severity …` / `⚠ Irreversible category …` when they apply · `Step 1 of 2 — read receipt issued … valid until <time>`. **Envelope 2 (ruling, after `--confirm-read`):** `Read acknowledged for crossing <id> (shown <t1>, acknowledged <t2>)` · `Step 2 of 2 — record the ruling: OPEN → FALSE_POSITIVE on LUM-N` · the note · the ⚠ consequence line | LUM-769. Two envelopes, two approvals: envelope 1's `confirmCommand` ends in `--confirm-read`, envelope 2's in `--confirm` (see Flags). The crossing is read first on every path and the command fails closed (exit 1, no write) when that read or a receipt request errors; a step flag without its receipt, `--confirm` with the stage-1 receipt, or both step flags at once are refused before any request; an already-matching ruling is a no-op (exit 0). Reverting to OPEN and repository suppression rules stay web-only; steward (milestone) crossings are not reachable. See [verify.md](verify.md). |
|
|
61
|
+
| `task deps rm <id> <edge>` | the resolved edge (short id, direction, other task, status, source) | [task-deps.md](task-deps.md) |
|
|
62
|
+
| `task artifact rm <task> <artifact-id>` | artifact id, title, kind; "irreversible" | [artifacts-figma.md](artifacts-figma.md) |
|
|
63
|
+
| `memory rm <memoryId>` | memory id, `[CATEGORY]`, a one-line content summary | [memory.md](memory.md) |
|
|
64
|
+
| `doc delete <doc>` | doc id + title; nested documents are deleted with it | [docs.md](docs.md) |
|
|
65
|
+
| `sprint delete <ref>` | sprint number + name; task count (tasks keep their data) | [sprints.md](sprints.md) |
|
|
66
|
+
| `sprint close <ref> --move-all` / `--backlog-all` | sprint; every unfinished task and where it goes | Without a mode flag and with unfinished tasks the command is a plain exit-1 refusal (pick a mode). [sprints.md](sprints.md) |
|
|
67
|
+
| `milestone delete <ref>` | milestone name; task count (tasks keep their data) | [milestones.md](milestones.md) |
|
|
68
|
+
| `worktree rm <LUM-N>` | path + branch; `⚠ … uncommitted changes … discarded` when dirty; whether the branch is kept or deleted | Dirty tree → `confirmCommand` carries `--force --confirm`. [worktree.md](worktree.md) |
|
|
69
|
+
| `doc rebuild-source <doc>` (when a source already exists) | the server's 409 reason; what `--force` would replace | `confirmCommand` carries `--force --confirm`. [doc-editing.md](doc-editing.md) |
|
|
70
|
+
|
|
71
|
+
## When the gate is human-only: `DONE_BLOCKED`, exit code 5
|
|
72
|
+
|
|
73
|
+
Not every refusal is something the user can approve on the spot. The server's DONE gates — an **unresolved send-back**, an **undispositioned boundary crossing**, a **blocking security finding** — are verdicts on the agent's own work, and the interested party may not adjudicate itself: nothing on `task update` clears them — no `--confirm`, no `--force`, nothing you can pass. Since LUM-769 a **boundary crossing** does have a terminal path, but it is a separate command and it is the user's: `lumo crossing disposition <id> --false-positive | --confirmed` walks the exit-4 protocol above (you relay the crossing, the user rules, you re-run the `confirmCommand`). Send-backs and security findings still have no CLI path at all.
|
|
74
|
+
|
|
75
|
+
What the CLI does instead: when `task update <id> --status done --confirm` is refused by one of these gates, it re-reads the task's acceptance status and open crossings, prints a structured error on **stdout** and exits **5**:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"status": "blocked",
|
|
80
|
+
"code": "DONE_BLOCKED",
|
|
81
|
+
"command": "task update",
|
|
82
|
+
"task": "LUM-48",
|
|
83
|
+
"message": "Cannot move this task to DONE — 1 undispositioned boundary-crossing (forbidden action taken during this task): 1 TEST_FILE_DELETED. …",
|
|
84
|
+
"blockers": [
|
|
85
|
+
{
|
|
86
|
+
"kind": "BOUNDARY_CROSSING",
|
|
87
|
+
"id": "cmtw…",
|
|
88
|
+
"severity": "MEDIUM",
|
|
89
|
+
"category": "TEST_FILE_DELETED",
|
|
90
|
+
"detail": "deleted __tests__/cli/old.test.ts"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"unconfirmed": [],
|
|
94
|
+
"remediation": [
|
|
95
|
+
"BOUNDARY_CROSSING: leave a rationale with `lumo crossing explain cmtw… --note \"…\"` (append-only; it does not clear anything), then relay each crossing to the user. Once they rule, record it with `lumo crossing disposition cmtw… --false-positive` or `--confirmed` — it prints an exit-4 envelope for the user to approve; never self-approve. The web panel also works: https://…/my-tasks/LUM-48#boundary-crossings"
|
|
96
|
+
],
|
|
97
|
+
"dispositionUrl": "https://…/my-tasks/LUM-48#boundary-crossings"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Field | Meaning |
|
|
102
|
+
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| `message` | The server's 409 text, verbatim. |
|
|
104
|
+
| `blockers` | One entry per item holding the gate: `SEND_BACK` (criterionId, statement, failedAtRound, rejectionReason), `BOUNDARY_CROSSING` (id, severity, category, detail), `SECURITY_FINDING` (findingId, severity, ruleId, filePath, line, prNumber, statement). Built from the same read models as `lumo task status`. |
|
|
105
|
+
| `unconfirmed` | Enrichment reads that failed (`boundary-crossings read failed: HTTP 500`). Non-empty means the blocker list may be incomplete — it never silently shrinks. |
|
|
106
|
+
| `remediation` | One line per blocker kind present, naming only human-side, append-only or user-approved paths: re-run `lumo verify`, `lumo crossing explain`, `lumo crossing disposition` (exit-4 envelope, the user rules), fix-and-push, the web disposition panel. Never a ready-to-run approval flag. |
|
|
107
|
+
|
|
108
|
+
**Exit 4 vs exit 5:** 4 means "the user must approve, then you can proceed"; 5 means "a human must adjudicate — nothing on this command moves it". On exit 5, relay `blockers` and `remediation` to the user. Do not retry `task update`, do not look for a flag on it, and do not reword or delete a failed criterion to get past a send-back (that is tampering and is audited). For a `BOUNDARY_CROSSING` blocker the adjudication can happen in the terminal — `lumo crossing disposition <id> …` is itself an exit-4 command, so the user's ruling still comes through the protocol, never from you. Once every blocker is cleared, re-run the original `task update … --confirm` (its envelope was already approved). A 409 that is not a DONE gate (e.g. a permission refusal) keeps the plain exit-1 text on stderr.
|
|
109
|
+
|
|
110
|
+
## Example exchange
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
lumo task update LUM-48 --status done
|
|
114
|
+
# exit 4, stdout:
|
|
115
|
+
# {
|
|
116
|
+
# "status": "confirmation_required",
|
|
117
|
+
# "command": "task update",
|
|
118
|
+
# "changes": [
|
|
119
|
+
# "Will move LUM-48 \"Panel refactor\" to DONE",
|
|
120
|
+
# "Status: IN_REVIEW → DONE",
|
|
121
|
+
# "#926 merged refactor: panel https://github.com/o/r/pull/926",
|
|
122
|
+
# "#930 open feat: wip https://github.com/o/r/pull/930",
|
|
123
|
+
# "⚠ 1 linked pull request not merged: #930 open"
|
|
124
|
+
# ],
|
|
125
|
+
# "confirmCommand": "lumo task update LUM-48 --status done --confirm"
|
|
126
|
+
# }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Agent → user: "Moving LUM-48 to DONE would change IN_REVIEW → DONE. PR #926 is merged, but **#930 is still open**. Confirm?" — and only after a yes:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
lumo task update LUM-48 --status done --confirm
|
|
133
|
+
```
|
|
@@ -9,7 +9,7 @@ The acceptance contract is a small set of structured criteria the task's work is
|
|
|
9
9
|
If `lumo task context` / session-start shows the draft reminder ("This task has no acceptance criteria yet. …") instead of a contract, you MUST draft and submit criteria before starting implementation:
|
|
10
10
|
|
|
11
11
|
1. Read the task description, comments, linked resources, and memory first — the contract distills what "done" means, so understand the task before writing it.
|
|
12
|
-
2. Draft **3–7 criteria** for a typical multi-file task (
|
|
12
|
+
2. Draft **3–7 criteria** for a typical multi-file task (drafting guidance only — the server enforces no count; if you genuinely need more, merge related checks instead). Scale the count down for small tasks (see "Scale the contract to the task size").
|
|
13
13
|
3. `lumo task criteria set <task> --file <criteria.json>` — submit.
|
|
14
14
|
|
|
15
15
|
### The reference-class block (outside view) — LUM-497
|
|
@@ -89,20 +89,15 @@ The 3–7 range is calibrated for typical multi-file tasks. Criterion count must
|
|
|
89
89
|
|
|
90
90
|
### judgeSteps — agent-drafted judging steps for HUMAN criteria
|
|
91
91
|
|
|
92
|
-
**`referentKind` —
|
|
92
|
+
**`referentKind` — derived by the system, not declared (LUM-733):**
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
You do not declare a referent kind. The server derives it from the checkpointer at write time and stores the result:
|
|
95
95
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
96
|
+
- MACHINE + a checkpointer that actually **consumes** an external tool (`git`/`gh`/`curl`/`psql`/`prisma migrate status`…, its exit or output reaching the verdict) → `EXTERNAL_FACT` — a fact the agent cannot author.
|
|
97
|
+
- MACHINE + anything else (`jest`/`vitest`/`tsc`/`node`/`tsx`, your own build or type-check) → `AGENT_CONSTRUCTED_STATE` — green is self-confirming, which is the honest kind for almost every code task's checks.
|
|
98
|
+
- HUMAN → no checkpointer to read; an optional `"referentKind": "EXTERNAL_FACT" | "AGENT_CONSTRUCTED_STATE"` is kept as-is, otherwise the row stays unclassified.
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- at **`criteria set`** — stores it but returns a non-rejecting ⚠ warning naming the criterion (re-ground or re-declare);
|
|
103
|
-
- at **`lumo verify`** — a PASS on it is **blocked with 422 (no round burned)**; the round does not land and the task does not move to IN_REVIEW until you either re-ground the checkpointer against a real external fact, or honestly re-declare it `AGENT_CONSTRUCTED_STATE`. Both fixes are free (no round consumed).
|
|
104
|
-
|
|
105
|
-
Don't reach for `EXTERNAL_FACT` to look stronger — a jest test is `AGENT_CONSTRUCTED_STATE`, full stop. Reserve `EXTERNAL_FACT` for checks that truly read external state, or use a HUMAN criterion for "a person ran the real system and observed X" (HUMAN is never mechanically downgraded).
|
|
100
|
+
A `referentKind` on a MACHINE item is accepted for backward compatibility and ignored. `PENDING_OUTCOME` is no longer a task-criterion kind (it remains on milestone exit criteria only) — leave post-delivery truths out of the encoded contract. There is no verify-time gate to trip: because the kind follows the check, a jest-checked criterion can never be stored as an "external fact".
|
|
106
101
|
|
|
107
102
|
A HUMAN criterion is judged by a person, not a checkpointer — so don't hand them a bare assertion ("the copy reads naturally") and make them reverse-engineer what to do. Attach **`judgeSteps`**: short, human-readable instructions the adjudication card renders verbatim (light markdown, URLs made clickable). Structured labour is yours; the human just follows the steps.
|
|
108
103
|
|
|
@@ -142,14 +137,12 @@ Two real-repo invariant examples — `prisma/migrations/` files never deleted (t
|
|
|
142
137
|
{
|
|
143
138
|
"statement": "No file under prisma/migrations/ is deleted by this change (vs origin/main)",
|
|
144
139
|
"verifierType": "MACHINE",
|
|
145
|
-
"checkpointer": "bash -c \"test -z \\\"$(git diff --diff-filter=D --name-only origin/main -- prisma/migrations/)\\\"\""
|
|
146
|
-
"referentKind": "EXTERNAL_FACT"
|
|
140
|
+
"checkpointer": "bash -c \"test -z \\\"$(git diff --diff-filter=D --name-only origin/main -- prisma/migrations/)\\\"\""
|
|
147
141
|
},
|
|
148
142
|
{
|
|
149
143
|
"statement": "Live-doc keeps its table structure after the edit (no rows/headings dropped)",
|
|
150
144
|
"verifierType": "MACHINE",
|
|
151
|
-
"checkpointer": "npx tsx scripts/verify-live-doc.ts <docId> docs/live-docs/<file>.md"
|
|
152
|
-
"referentKind": "AGENT_CONSTRUCTED_STATE"
|
|
145
|
+
"checkpointer": "npx tsx scripts/verify-live-doc.ts <docId> docs/live-docs/<file>.md"
|
|
153
146
|
}
|
|
154
147
|
]
|
|
155
148
|
```
|
|
@@ -167,8 +160,7 @@ One invariant criterion is usually enough — it's the guardrail, not the whole
|
|
|
167
160
|
{
|
|
168
161
|
"statement": "PUT /api/tasks/[id]/criteria rejects a second AGENT_DRAFT submission with 409",
|
|
169
162
|
"verifierType": "MACHINE",
|
|
170
|
-
"checkpointer": "npx jest __tests__/task-criteria.service.test.ts -t 'agent lock'"
|
|
171
|
-
"referentKind": "AGENT_CONSTRUCTED_STATE"
|
|
163
|
+
"checkpointer": "npx jest __tests__/task-criteria.service.test.ts -t 'agent lock'"
|
|
172
164
|
},
|
|
173
165
|
{
|
|
174
166
|
"statement": "The criteria section reads naturally as part of the task statement",
|
|
@@ -180,7 +172,6 @@ One invariant criterion is usually enough — it's the guardrail, not the whole
|
|
|
180
172
|
"statement": "Session-start injection shows the contract ahead of memory",
|
|
181
173
|
"verifierType": "MACHINE",
|
|
182
174
|
"checkpointer": "npx jest __tests__/cli/hook-runner-session-start-stdout.test.ts",
|
|
183
|
-
"referentKind": "AGENT_CONSTRUCTED_STATE",
|
|
184
175
|
"evidenceRequired": true
|
|
185
176
|
}
|
|
186
177
|
]
|
|
@@ -191,7 +182,7 @@ Fields:
|
|
|
191
182
|
- `statement` — required, ≤2000 chars.
|
|
192
183
|
- `verifierType` — `"MACHINE"` | `"HUMAN"`.
|
|
193
184
|
- `checkpointer` — required for MACHINE.
|
|
194
|
-
- `referentKind` —
|
|
185
|
+
- `referentKind` — optional and advisory; the stored kind is derived from the checkpointer (see "referentKind" above). Only meaningful on a HUMAN criterion (`"EXTERNAL_FACT"` | `"AGENT_CONSTRUCTED_STATE"`).
|
|
195
186
|
- `evidenceRequired` — optional, default false.
|
|
196
187
|
- `judgeSteps` — optional, ≤2000 chars; agent-drafted human-judging steps for a HUMAN criterion (see "judgeSteps" above).
|
|
197
188
|
- `id` — only in `--human` revisions (see below).
|
|
@@ -263,7 +254,7 @@ lumo criteria audit
|
|
|
263
254
|
- `EXTERNAL_FACT` — declared as externally observable (git SHA, CI status, DB row) and the checkpointer invokes real external tooling
|
|
264
255
|
- `AGENT_CONSTRUCTED_STATE` — passes by checking output the agent itself produced
|
|
265
256
|
- `PENDING_OUTCOME` — deferred to post-hoc falsifier
|
|
266
|
-
- `UNVERIFIED_ASSERTION` — declared `EXTERNAL_FACT`
|
|
257
|
+
- `UNVERIFIED_ASSERTION` — a legacy row declared `EXTERNAL_FACT` (before LUM-733 derivation) whose checkpointer does **not** actually invoke external tooling (git/CI/HTTP); reported as-is. New rows can't land here — the kind is derived from the checkpointer at write time (see "referentKind")
|
|
267
258
|
- `UNCLASSIFIED` — legacy rows predating the `referentKind` field (null in DB)
|
|
268
259
|
|
|
269
260
|
2. **Self-confirming-green headline ratio** — `(AGENT_CONSTRUCTED_STATE + UNVERIFIED_ASSERTION) / classified`. Criteria in these two buckets pass by confirming only the agent's own work, not an independent external state.
|
|
@@ -121,24 +121,26 @@ lumo doc diff cmd_xxx --file docs/live-docs/research-intake-ledger.md
|
|
|
121
121
|
|
|
122
122
|
The **recovery path for a source-less doc**. When a doc has no stored `sourceMarkdown` — a web HTML-direct edit or revision restore nulled it, or the doc predates source storage — every markdown write path (`--raw`, `--section`, `doc patch`, `doc append --section`, `doc diff`) is locked. This regenerates a valid source by serializing the **stored HTML structure model** back to markdown with a **lossless serializer that round-trips tables/rows/headings** (the default `doc show` render flattens tables, so it was never a safe rebuild base). Only the `sourceMarkdown` column is backfilled; the rendered body is untouched, so the doc reads identically and you just regain the edit base.
|
|
123
123
|
|
|
124
|
-
| Flag | Type | Notes
|
|
125
|
-
| ------------------- | ------- |
|
|
126
|
-
| `--allow-shrink` | boolean | Commit even if the rebuilt source re-renders with fewer tables/rows/headings than the stored body (default: 422 reject).
|
|
127
|
-
| `--force` | boolean | Re-derive even when a source already exists
|
|
128
|
-
| `--
|
|
124
|
+
| Flag | Type | Notes |
|
|
125
|
+
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
126
|
+
| `--allow-shrink` | boolean | Commit even if the rebuilt source re-renders with fewer tables/rows/headings than the stored body (default: 422 reject). |
|
|
127
|
+
| `--force` | boolean | Re-derive even when a source already exists. Without it an existing source yields exit 4 + a confirmation envelope whose `confirmCommand` carries `--force --confirm` ([confirmation.md](confirmation.md)). |
|
|
128
|
+
| `--confirm` | boolean | The user approved replacing the existing source; pair it with `--force` as the envelope instructs. |
|
|
129
|
+
| `--if-revision <n>` | int | Only apply if the body is still at this revision (from `doc show`). |
|
|
129
130
|
|
|
130
|
-
The rebuild is **structure-guarded** (the same guard as `doc update`/`doc patch`): if the serializer would drop any table/row/heading, it is rejected with **422** rather than silently committing a flattened source — `--allow-shrink` is the explicit escape hatch. A doc that already has a source is refused
|
|
131
|
+
The rebuild is **structure-guarded** (the same guard as `doc update`/`doc patch`): if the serializer would drop any table/row/heading, it is rejected with **422** rather than silently committing a flattened source — `--allow-shrink` is the explicit escape hatch. A doc that already has a source is refused by the server (409); the CLI turns that refusal into a **confirmation envelope** (exit 4, `changes` = the server's reason + what `--force` would replace) so the user sees it before anything is overwritten.
|
|
131
132
|
|
|
132
133
|
```bash
|
|
133
|
-
lumo doc rebuild-source cmd_xxx
|
|
134
|
-
lumo doc rebuild-source cmd_xxx
|
|
134
|
+
lumo doc rebuild-source cmd_xxx # restore a source-less doc; --raw works after
|
|
135
|
+
lumo doc rebuild-source cmd_xxx # source exists → exit 4 + envelope, nothing written
|
|
136
|
+
lumo doc rebuild-source cmd_xxx --force --confirm # re-derive after the user approved the envelope
|
|
135
137
|
```
|
|
136
138
|
|
|
137
139
|
### When to suggest `doc rebuild-source`
|
|
138
140
|
|
|
139
141
|
- A `--raw` / `--section` / `doc patch` / `doc diff` call errored with "no stored markdown source" — rebuild, then retry. This is the first thing to try, not a manual reconstruction.
|
|
140
142
|
- A table-heavy live doc (e.g. a `docs/live-docs/` registry) lost its source after a web operation and the markdown write path is locked.
|
|
141
|
-
- Do **not** run it on a doc that already has a good source unless the user explicitly wants to re-derive it (then
|
|
143
|
+
- Do **not** run it on a doc that already has a good source unless the user explicitly wants to re-derive it (then re-run the envelope's `confirmCommand`, i.e. `--force --confirm`) — it replaces the byte-faithful source with a serializer-derived one.
|
|
142
144
|
|
|
143
145
|
## Out of scope (CLI v1)
|
|
144
146
|
|
|
@@ -164,12 +164,13 @@ lumo doc move "Sub-doc" --root
|
|
|
164
164
|
- User says "move doc X under Y", "reparent X to root", "promote X to top level".
|
|
165
165
|
- After `doc create`, if the user realizes the new doc should live elsewhere — suggest `doc move` rather than recreating.
|
|
166
166
|
|
|
167
|
-
## `lumo doc delete <doc> --
|
|
167
|
+
## `lumo doc delete <doc> --confirm` — delete a document
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
Deletes the document **and every document nested under it**. Without `--confirm` the CLI looks the doc up and exits **4** with a confirmation envelope (`Will delete document cmd_xxx "Title"` + the nested-docs rule) — nothing is deleted; relay `changes` to the user and re-run `confirmCommand` on approval ([confirmation.md](confirmation.md)). `--yes` is a legacy alias.
|
|
170
170
|
|
|
171
171
|
```bash
|
|
172
|
-
lumo doc delete cmd_xxx
|
|
172
|
+
lumo doc delete cmd_xxx # exit 4 + envelope
|
|
173
|
+
lumo doc delete cmd_xxx --confirm # after the user approved
|
|
173
174
|
```
|
|
174
175
|
|
|
175
176
|
## `lumo doc bind <doc> <task>` / `lumo doc unbind <doc> <task>` — task linkage
|
|
@@ -32,7 +32,7 @@ lumo project memory add [<project>] --category convention --rule "..." --applies
|
|
|
32
32
|
# Single-memory ops (memoryId from `... memory list` column 1)
|
|
33
33
|
lumo memory show <memoryId> # show one memory's full card by id
|
|
34
34
|
lumo memory promote <memoryId> # TASK → PROJECT
|
|
35
|
-
lumo memory rm <memoryId> --
|
|
35
|
+
lumo memory rm <memoryId> --confirm # hard delete (without --confirm: exit 4 + envelope)
|
|
36
36
|
|
|
37
37
|
# Downsync team memory into the local Claude Code memory store
|
|
38
38
|
lumo memory sync # write team/<id>.md + a managed MEMORY.md block
|
|
@@ -68,9 +68,11 @@ lumo project memory add lumo --category procedural --workflow "Regenerate the CL
|
|
|
68
68
|
# Curate
|
|
69
69
|
lumo memory show cmpi19iqabc123
|
|
70
70
|
lumo memory promote cmpi19iqabc123
|
|
71
|
-
lumo memory rm cmpi19iqabc123 --
|
|
71
|
+
lumo memory rm cmpi19iqabc123 --confirm
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
`memory rm` is gated by the confirmation protocol ([confirmation.md](confirmation.md)): without `--confirm` it fetches the card and exits **4** with an envelope (`Will hard-delete memory <id> [TRAP]` · `Content: <first line>` · no undo) and deletes nothing. Show that to the user first; `--yes` is a legacy alias of `--confirm`.
|
|
75
|
+
|
|
74
76
|
### `lumo memory show <id>` (progressive disclosure)
|
|
75
77
|
|
|
76
78
|
Fetches one memory's full card by id from the server and prints its category tag
|
|
@@ -194,10 +194,11 @@ lumo milestone criteria verdict "Q3 Launch" cmexit0002 --unmet --note "read mode
|
|
|
194
194
|
|
|
195
195
|
### `lumo milestone delete <identifier>` — delete a milestone
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
Gated by the confirmation protocol ([confirmation.md](confirmation.md)): without `--confirm` the CLI exits **4** with an envelope (`Will delete milestone "Q3 Launch"` · `12 tasks under it keep their data; only milestoneId is cleared`) and deletes nothing — relay it to the user and re-run `confirmCommand` on approval. `--yes` is a legacy alias. Tasks under the milestone keep their data; their `milestoneId` is cleared.
|
|
198
198
|
|
|
199
199
|
```bash
|
|
200
|
-
lumo milestone delete "Q3 Launch"
|
|
200
|
+
lumo milestone delete "Q3 Launch" # exit 4 + envelope
|
|
201
|
+
lumo milestone delete "Q3 Launch" --confirm # after the user approved
|
|
201
202
|
```
|
|
202
203
|
|
|
203
204
|
### `lumo milestone archive <identifier>` — soft-archive a milestone
|
|
@@ -14,7 +14,7 @@ There is **no `SATISFIED` / `PASS`**. "N sprints and nobody touched it" is the _
|
|
|
14
14
|
## Collection (where signals come from)
|
|
15
15
|
|
|
16
16
|
- **Automatic** — a DONE task reopened (the lineage `REWORKED` transition) is folded into the well as a `REOPENED` signal. No action needed; it happens server-side.
|
|
17
|
-
- **
|
|
17
|
+
- **Git-derived** — a revert (or a content reversal) of the delivery's commits landing on the default branch is recorded from the push webhook as `REVERTED` / `DOWNSTREAM_REDIRECT` (LUM-607). No manual recording path exists any more: the former `lumo outcome record` command was removed in LUM-733 (it was never used — 0 MANUAL signals all-time); CI-derived signals (`CI_REGRESSION` / `ROLLED_BACK`) are a follow-up.
|
|
18
18
|
|
|
19
19
|
## `lumo outcome show <task>`
|
|
20
20
|
|
|
@@ -26,18 +26,6 @@ lumo outcome show LUM-42
|
|
|
26
26
|
|
|
27
27
|
An empty well prints `INCONCLUSIVE` with the reminder that silence is not a pass. A non-empty well prints `REJECTED` and lists each signal (date, kind, source, note).
|
|
28
28
|
|
|
29
|
-
## `lumo outcome record <task> --note "<what reality did>" [--kind <kind>]`
|
|
30
|
-
|
|
31
|
-
Record one human-observed post-hoc rejection. Append-only — every call inserts a new signal; nothing is ever mutated or cleared.
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
lumo outcome record LUM-42 --note "reverted in #812 after a prod incident" --kind reverted
|
|
35
|
-
lumo outcome record LUM-42 --note "downstream rewrote the API shape this task introduced" --kind downstream_redirect
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
- `--kind` (case-insensitive, default `manual`): `reverted | rolled_back | ci_regression | downstream_redirect | bypassed | manual`. `reopened` is **not** a manual kind — it is owned by the automatic lineage fold.
|
|
39
|
-
- `--occurred-at <iso>` — when the event actually happened (defaults to now).
|
|
40
|
-
|
|
41
29
|
## `lumo outcome rate [--min N] [--json]`
|
|
42
30
|
|
|
43
31
|
The workspace-level **trust × post-hoc-fate** join (LUM-603, LUM-606). For every delivery that has a frozen forecast snapshot, it buckets the delivery by its **delivery-time verification friction** — two raw counts (`verificationRounds`, `sendBackCount`) frozen at delivery from the append-only `VerificationRun` log, cut at `capturedAt`, then bucketed value-neutrally into `no-verification` / `single-round` / `multi-round-or-sendback` — and reports each bucket's post-hoc **REJECTED** rate from the well. The friction axis replaced the original sample-size forecast-confidence axis (LUM-606), which saturated: every mature-project delivery landed in `high`, so `high`-vs-`low` could never compare. The question it answers once data is sufficient: _do deliveries that took more verification friction get rejected by reality more (fragility) or less (scrutiny) often?_ The bucket names carry **no** good/bad direction — the correlation, not the label, decides.
|
|
@@ -59,7 +47,6 @@ This is the falsifier discipline applied at the **query layer** — it refuses t
|
|
|
59
47
|
|
|
60
48
|
## When to suggest
|
|
61
49
|
|
|
62
|
-
- A teammate says a shipped task **was reverted / rolled back / broke prod / got redone / was bypassed** — record it with `lumo outcome record` so the well carries reality's verdict.
|
|
63
50
|
- Auditing whether a "done" task actually held up — `lumo outcome show <task>` reads the well.
|
|
64
51
|
- Asking whether **verification friction predicts post-hoc fate** (do harder-to-verify deliveries fail more, or less?) — `lumo outcome rate`. Expect `inconclusive` until the well fills; it will never print a correlation the sample can't support.
|
|
65
52
|
- **Never** use it to mark something good: the well has no positive verdict by design. To assert a delivery met its contract, that is the acceptance loop (`lumo verify` / `lumo task status`), not the well.
|
|
@@ -16,6 +16,11 @@ Invoked bare (`lumo plan`) it starts a run; `lumo plan --abandon-active` clears
|
|
|
16
16
|
|
|
17
17
|
**When to suggest**: the user wants to turn the parked idea pool into a plan — "跑一下转换器", "start a planning run", "把想法变成计划".
|
|
18
18
|
|
|
19
|
+
```bash
|
|
20
|
+
lumo plan
|
|
21
|
+
lumo plan --abandon-active
|
|
22
|
+
```
|
|
23
|
+
|
|
19
24
|
## `lumo plan status`
|
|
20
25
|
|
|
21
26
|
Print the active run's current stage — either the working segment or the open `*_READY` gate — plus the deep-link to act on its next gate. With no active run, prompts to run `lumo plan`.
|