@codyswann/lisa 2.282.0 → 2.284.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/all/create-only/.lisa/DEPENDENCY_DECISIONS.md +175 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +28 -2
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/plugins/lisa/rules/eager/dependency-decision-records.md +32 -0
- package/plugins/lisa/rules/eager/dependency-trust-classes.md +43 -0
- package/plugins/lisa/rules/reference/dependency-decision-records.md +140 -0
- package/plugins/lisa/rules/reference/dependency-trust-classes.md +243 -0
- package/plugins/lisa/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/rules/eager/dependency-decision-records.md +32 -0
- package/plugins/lisa-copilot/rules/eager/dependency-trust-classes.md +43 -0
- package/plugins/lisa-copilot/rules/reference/dependency-decision-records.md +140 -0
- package/plugins/lisa-copilot/rules/reference/dependency-trust-classes.md +243 -0
- package/plugins/lisa-copilot/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/dependency-decision-records-reference.mdc +145 -0
- package/plugins/lisa-cursor/rules/dependency-decision-records.mdc +37 -0
- package/plugins/lisa-cursor/rules/dependency-trust-classes-reference.mdc +248 -0
- package/plugins/lisa-cursor/rules/dependency-trust-classes.mdc +48 -0
- package/plugins/lisa-cursor/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/eager/dependency-decision-records.md +32 -0
- package/plugins/src/base/rules/eager/dependency-trust-classes.md +43 -0
- package/plugins/src/base/rules/reference/dependency-decision-records.md +140 -0
- package/plugins/src/base/rules/reference/dependency-trust-classes.md +243 -0
- package/plugins/src/base/skills/lisa-task-decomposition/SKILL.md +26 -0
- package/ui/index.html +195 -43
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Dependency Trust Classes
|
|
2
|
+
|
|
3
|
+
Without named classes, every third-party package sits in one implicit bucket:
|
|
4
|
+
"we installed it, so presumably it's fine." That bucket makes a payment SDK and
|
|
5
|
+
a code formatter look identical at review time, and it forces every dependency
|
|
6
|
+
conversation to re-argue trust from first principles.
|
|
7
|
+
|
|
8
|
+
Trust classes fix that. Each class states, in plain language, **why we can trust
|
|
9
|
+
that kind of dependency**, and names **the one event that would trigger human
|
|
10
|
+
review**. A dependency's class is the answer to the
|
|
11
|
+
"Why we believe it's safe (trust basis)" field in
|
|
12
|
+
`.lisa/DEPENDENCY_DECISIONS.md` — the record says what
|
|
13
|
+
this dependency is and what would catch a bad update; the class says what bar it
|
|
14
|
+
had to clear to be here at all.
|
|
15
|
+
|
|
16
|
+
Exactly one class per dependency. If two seem to fit, take the lower-trust one —
|
|
17
|
+
the requirements are strictly stronger, and being over-careful about a formatter
|
|
18
|
+
costs a review cycle while being under-careful about an auth client costs users.
|
|
19
|
+
|
|
20
|
+
## The five review inputs
|
|
21
|
+
|
|
22
|
+
Every class fixes the same five inputs. What changes between classes is how
|
|
23
|
+
demanding each one is:
|
|
24
|
+
|
|
25
|
+
- **Capability owner** — who is accountable when this breaks. A role for
|
|
26
|
+
high-trust classes; a named person for low-trust ones, because "the platform
|
|
27
|
+
team" cannot be paged at 2am.
|
|
28
|
+
- **Update cadence** — how often the entry is re-read and the version re-judged.
|
|
29
|
+
- **Detection evidence** — the named check that fails if an update breaks the
|
|
30
|
+
owned capability. Stronger classes demand evidence *we* own, not upstream's
|
|
31
|
+
test suite.
|
|
32
|
+
- **Replacement-cost threshold** — the point past which the cost itself is the
|
|
33
|
+
finding. High replacement cost is acceptable in a high-trust class and is an
|
|
34
|
+
escalation in a low-trust one.
|
|
35
|
+
- **Product/human ratification** — whether a human has to say yes before the
|
|
36
|
+
dependency is added, upgraded, or kept. This is the gate, and it is deliberate
|
|
37
|
+
that the lower-trust and higher-exposure classes carry it.
|
|
38
|
+
|
|
39
|
+
## The six classes
|
|
40
|
+
|
|
41
|
+
### 1. Mature ecosystem primitive
|
|
42
|
+
|
|
43
|
+
**Why we can trust it:** so many other projects depend on it that a bad release
|
|
44
|
+
is usually found, reported, and fixed by someone else before it reaches us. It
|
|
45
|
+
has an identifiable maintaining organization, a published release cadence, and a
|
|
46
|
+
documented process for handling security reports. Trust here comes from the size
|
|
47
|
+
of the crowd standing in front of us, not from us having read the code.
|
|
48
|
+
|
|
49
|
+
Examples in kind: a language's canonical test runner, a foundation-maintained
|
|
50
|
+
linter, a mainstream UI framework.
|
|
51
|
+
|
|
52
|
+
- **Capability owner:** a role or team is sufficient.
|
|
53
|
+
- **Update cadence:** re-read at each major upgrade, and at least every 12
|
|
54
|
+
months.
|
|
55
|
+
- **Detection evidence:** an existing CI check must fail if the owned capability
|
|
56
|
+
breaks. Naming an upstream test suite is acceptable here and only here.
|
|
57
|
+
- **Replacement-cost threshold:** high replacement cost is accepted. That is the
|
|
58
|
+
bargain — we take deep coupling in exchange for the crowd's scrutiny.
|
|
59
|
+
- **Ratification:** not required to add or to take a minor/patch upgrade.
|
|
60
|
+
|
|
61
|
+
**Human review is triggered when:** maintainership changes hands or the project
|
|
62
|
+
is archived, or a security advisory goes unfixed past the project's own
|
|
63
|
+
published response window. Either event removes the crowd, which was the whole
|
|
64
|
+
basis for the trust — reclassify rather than re-trust.
|
|
65
|
+
|
|
66
|
+
### 2. Fast-moving standard implementation
|
|
67
|
+
|
|
68
|
+
**Why we can trust it:** it is the standard implementation of a protocol, spec,
|
|
69
|
+
or platform we have deliberately decided not to own — a cloud SDK, an API
|
|
70
|
+
client, a framework tracking a moving platform. We trust the *standard*; we do
|
|
71
|
+
not trust the release we happen to be on, because the project moves faster than
|
|
72
|
+
our review cycle does. Trust here is conditional on us keeping up.
|
|
73
|
+
|
|
74
|
+
- **Capability owner:** a named team that owns staying current.
|
|
75
|
+
- **Update cadence:** re-read at every minor upgrade, and no less than
|
|
76
|
+
quarterly. A dependency in this class going quiet for a year is itself a
|
|
77
|
+
finding.
|
|
78
|
+
- **Detection evidence:** an automated test **we** own that exercises the owned
|
|
79
|
+
capability. Upstream's suite does not count — it tests their contract, not our
|
|
80
|
+
use of it.
|
|
81
|
+
- **Replacement-cost threshold:** replacement cost must stay moderate. Keep the
|
|
82
|
+
coupling behind our own boundary so a forced migration is a rewrite of the
|
|
83
|
+
boundary, not of the application.
|
|
84
|
+
- **Ratification:** required for any major upgrade that changes user-visible
|
|
85
|
+
behavior.
|
|
86
|
+
|
|
87
|
+
**Human review is triggered when:** two consecutive major versions ship that we
|
|
88
|
+
did not adopt inside the cadence window. At that point we are pinned to
|
|
89
|
+
unsupported software and the decision — catch up, replace, or accept the
|
|
90
|
+
exposure — belongs to a human.
|
|
91
|
+
|
|
92
|
+
### 3. Build/development tool
|
|
93
|
+
|
|
94
|
+
**Why we can trust it:** it never runs in production and never touches customer
|
|
95
|
+
data. If it ships a bad update, developers notice within one build, and the
|
|
96
|
+
worst case is lost engineering time rather than a user-visible failure. The
|
|
97
|
+
blast radius is what earns the trust, not the maintainer.
|
|
98
|
+
|
|
99
|
+
- **Capability owner:** a role or team is sufficient.
|
|
100
|
+
- **Update cadence:** re-read at each major upgrade, and at least every 12
|
|
101
|
+
months.
|
|
102
|
+
- **Detection evidence:** the build, lint, or test job the tool powers. It fails
|
|
103
|
+
loudly and immediately, which is the point.
|
|
104
|
+
- **Replacement-cost threshold:** high cost is accepted — swapping a build tool
|
|
105
|
+
is disruptive but never urgent.
|
|
106
|
+
- **Ratification:** not required.
|
|
107
|
+
|
|
108
|
+
**Human review is triggered when:** the tool gains reach it did not have —
|
|
109
|
+
running in production, reading secrets, or reading CI credentials. The moment
|
|
110
|
+
that happens the blast-radius argument is void: reclassify it as a
|
|
111
|
+
runtime-critical service client and apply that class's requirements immediately.
|
|
112
|
+
|
|
113
|
+
### 4. Runtime-critical service client
|
|
114
|
+
|
|
115
|
+
**Why we can trust it:** honestly, we mostly don't. This class covers anything
|
|
116
|
+
that reaches users, their data, or money in production — payment SDKs, auth
|
|
117
|
+
libraries, database drivers, service clients on the request path. Even a mature,
|
|
118
|
+
well-run project lands in this class if a bad update reaches production, because
|
|
119
|
+
maturity does not shrink blast radius. Trust here is bought with our own
|
|
120
|
+
evidence and a human's signature, not the vendor's reputation.
|
|
121
|
+
|
|
122
|
+
- **Capability owner:** a named accountable person, not a team.
|
|
123
|
+
- **Update cadence:** re-judged at every version change. Versions are pinned
|
|
124
|
+
exactly, so upgrades are always deliberate.
|
|
125
|
+
- **Detection evidence:** an integration or end-to-end test that exercises the
|
|
126
|
+
real capability, **plus** a production monitor that would notice failure in
|
|
127
|
+
the wild. "Nothing would catch it" is not an acceptable answer in this class —
|
|
128
|
+
it is a blocker.
|
|
129
|
+
- **Replacement-cost threshold:** replacement cost must be written down, never
|
|
130
|
+
`_Not yet decided_`. If nobody can estimate it, we do not know how trapped we
|
|
131
|
+
are, and that unknown is the finding.
|
|
132
|
+
- **Ratification:** **product/human ratification is required** before adding the
|
|
133
|
+
dependency and before any major upgrade.
|
|
134
|
+
|
|
135
|
+
**Human review is triggered when:** any version changes, any security advisory
|
|
136
|
+
is published, or the vendor has a service incident. Every one of those is a
|
|
137
|
+
human decision in this class — that is what makes it the strictest.
|
|
138
|
+
|
|
139
|
+
### 5. Thin wrapper suitable for in-house ownership
|
|
140
|
+
|
|
141
|
+
**Why we can trust it:** it is small enough that we could read all of it in an
|
|
142
|
+
afternoon and own it outright. Safety is not really the question; whether it is
|
|
143
|
+
earning its keep is. A dependency we could write in a day still costs us a
|
|
144
|
+
supply-chain entry, a transitive tree, and an upgrade obligation forever.
|
|
145
|
+
|
|
146
|
+
- **Capability owner:** the team that would inherit the code if we in-housed it.
|
|
147
|
+
If no team will claim it, do not add it.
|
|
148
|
+
- **Update cadence:** re-read at every upgrade — there should be few.
|
|
149
|
+
- **Detection evidence:** our own unit tests covering the wrapped behavior. They
|
|
150
|
+
are cheap here precisely because the surface is small, and they are what makes
|
|
151
|
+
in-housing a one-day job later instead of a rewrite.
|
|
152
|
+
- **Replacement-cost threshold:** roughly one day. Under it, the default is to
|
|
153
|
+
in-house the code rather than take the dependency.
|
|
154
|
+
- **Ratification:** **required to keep it** when replacement cost is under the
|
|
155
|
+
threshold. Note the inversion: the human signs off on the *exception* — taking
|
|
156
|
+
a dependency we could trivially own — not on the removal.
|
|
157
|
+
|
|
158
|
+
**Human review is triggered when:** the package goes unmaintained, or its
|
|
159
|
+
transitive dependency tree grows larger than the code it wraps. Either way we
|
|
160
|
+
are now carrying more supply chain than capability, and in-housing should be
|
|
161
|
+
reconsidered on purpose.
|
|
162
|
+
|
|
163
|
+
### 6. Temporary/experimental dependency
|
|
164
|
+
|
|
165
|
+
**Why we can trust it:** we don't, and we say so. This class exists so a spike,
|
|
166
|
+
a prototype, or a stopgap can move fast without silently becoming permanent. It
|
|
167
|
+
is admitted on a clock: a written expiry date and a named exit — replace,
|
|
168
|
+
in-house, promote to another class, or remove.
|
|
169
|
+
|
|
170
|
+
- **Capability owner:** the person who introduced it, by name. Ownership does
|
|
171
|
+
not transfer to a team while the dependency is in this class.
|
|
172
|
+
- **Update cadence:** reviewed at the stated expiry date, which is at most one
|
|
173
|
+
quarter out. No expiry date means it does not belong in this class.
|
|
174
|
+
- **Detection evidence:** "nothing would catch it" is tolerated **only** while
|
|
175
|
+
exposure stays out of production. The moment it reaches production, the
|
|
176
|
+
runtime-critical requirements apply.
|
|
177
|
+
- **Replacement-cost threshold:** must be low by construction. Anything
|
|
178
|
+
expensive to remove is not temporary — it is a permanent dependency wearing a
|
|
179
|
+
temporary label, and it should be classified honestly on day one.
|
|
180
|
+
- **Ratification:** **required to extend past the expiry date** or to promote it
|
|
181
|
+
into any other class. An expiry that slides without a human saying yes is how
|
|
182
|
+
a prototype becomes production.
|
|
183
|
+
|
|
184
|
+
**Human review is triggered when:** the expiry date passes, or the dependency
|
|
185
|
+
starts running in production or touching user data — whichever happens first.
|
|
186
|
+
|
|
187
|
+
## Ratification, summarized
|
|
188
|
+
|
|
189
|
+
Ratification is not a formality; it is the point where a human owns the residual
|
|
190
|
+
risk. Required for:
|
|
191
|
+
|
|
192
|
+
- **Runtime-critical service client** — to add, and for every major upgrade.
|
|
193
|
+
- **Temporary/experimental dependency** — to extend past expiry or to promote.
|
|
194
|
+
- **Thin wrapper suitable for in-house ownership** — to keep it rather than
|
|
195
|
+
in-house it.
|
|
196
|
+
- **Fast-moving standard implementation** — for a major upgrade that changes
|
|
197
|
+
user-visible behavior.
|
|
198
|
+
|
|
199
|
+
Not required for mature ecosystem primitives or build/development tools on
|
|
200
|
+
routine adds and upgrades. Those two classes are where the crowd and the blast
|
|
201
|
+
radius do the work a human would otherwise have to do.
|
|
202
|
+
|
|
203
|
+
## Naming a class at planning time
|
|
204
|
+
|
|
205
|
+
A work item that proposes adding a new material dependency must, before it is
|
|
206
|
+
buildable, name the dependency's trust class and state that it will update the
|
|
207
|
+
`.lisa/DEPENDENCY_DECISIONS.md` entry in the same change. This is enforced at
|
|
208
|
+
decomposition time by the `lisa-task-decomposition` skill, which rejects a work
|
|
209
|
+
unit proposing a material dependency with no named class.
|
|
210
|
+
|
|
211
|
+
The class is what makes the rest of the ticket reviewable: it tells the reviewer
|
|
212
|
+
which evidence to demand and whether a human has to ratify before the work
|
|
213
|
+
starts, rather than discovering both at the end.
|
|
214
|
+
|
|
215
|
+
Naming a class is not a formality either. If nobody can pick one, that is the
|
|
216
|
+
finding — an unclassifiable dependency is usually one nobody has thought about,
|
|
217
|
+
and it should be resolved before the work item is accepted rather than after the
|
|
218
|
+
package is installed.
|
|
219
|
+
|
|
220
|
+
## Reclassification
|
|
221
|
+
|
|
222
|
+
Trust classes describe the dependency as it is used today, not as it was
|
|
223
|
+
introduced. When exposure changes — a build tool starts running in production, a
|
|
224
|
+
prototype ships to users, a thin wrapper grows a large transitive tree — move it
|
|
225
|
+
to the correct class and apply the new requirements immediately. Update the
|
|
226
|
+
`Last reviewed` date on the record entry when you do.
|
|
227
|
+
|
|
228
|
+
Reclassifying downward (to a lower-trust class) is never a demotion of the
|
|
229
|
+
dependency. It is an admission that its blast radius grew, which is a fact about
|
|
230
|
+
us, not about the maintainers.
|
|
231
|
+
|
|
232
|
+
## Agent parity
|
|
233
|
+
|
|
234
|
+
Trust classes are a governed markdown rule and a decomposition-time expectation,
|
|
235
|
+
not a runtime behavior, so Claude Code, Codex, Cursor, OpenCode, Antigravity,
|
|
236
|
+
and Copilot all reach them identically through the shared rules mirror and the
|
|
237
|
+
same `lisa-task-decomposition` skill.
|
|
238
|
+
|
|
239
|
+
The documented gap, uniform across all six runtimes: no agent runtime enforces
|
|
240
|
+
that a dependency carries a correct class. Nothing fails a build when a package
|
|
241
|
+
is installed with no class named, and nothing detects that a build tool quietly
|
|
242
|
+
started running in production. Classification is carried by this rule, the
|
|
243
|
+
decomposition skill, and review — not by a hook or a lint gate.
|
|
@@ -74,6 +74,31 @@ Each task must have a verification method. Choose the most appropriate:
|
|
|
74
74
|
- Prefer independent tasks that can run in parallel where possible
|
|
75
75
|
- Flag external dependencies (other teams, services, permissions, data) that may block progress
|
|
76
76
|
|
|
77
|
+
### 4.5. Classify Any New Material Dependency
|
|
78
|
+
|
|
79
|
+
Step 4 maps dependencies *between tasks*. This step covers third-party
|
|
80
|
+
dependencies a task proposes to **add**.
|
|
81
|
+
|
|
82
|
+
A dependency is **material** if its failure, disappearance, or bad update would
|
|
83
|
+
break something a user can see, or would cost real time to replace. If a work
|
|
84
|
+
unit proposes adding one, the work unit must, before it is buildable:
|
|
85
|
+
|
|
86
|
+
1. **Name its trust class** — exactly one of: mature ecosystem primitive,
|
|
87
|
+
fast-moving standard implementation, build/development tool, runtime-critical
|
|
88
|
+
service client, thin wrapper suitable for in-house ownership, or
|
|
89
|
+
temporary/experimental dependency. See the `dependency-trust-classes` rule
|
|
90
|
+
for what each class means and why it is trusted.
|
|
91
|
+
2. **State the class's required evidence** — the detection evidence that class
|
|
92
|
+
demands, and whether product/human ratification is required before the work
|
|
93
|
+
starts. Runtime-critical service clients and expiry extensions on temporary
|
|
94
|
+
dependencies always require ratification; a work unit that needs it and does
|
|
95
|
+
not say so is not ready.
|
|
96
|
+
3. **Include updating `.lisa/DEPENDENCY_DECISIONS.md`** in its acceptance
|
|
97
|
+
criteria, so the record entry lands in the same change as the dependency.
|
|
98
|
+
|
|
99
|
+
If nobody can pick a class, that is the finding — resolve it before accepting
|
|
100
|
+
the work unit, not after the package is installed.
|
|
101
|
+
|
|
77
102
|
### 5. Determine Execution Order
|
|
78
103
|
|
|
79
104
|
- Place foundational tasks first (types, schemas, interfaces, shared utilities)
|
|
@@ -121,6 +146,7 @@ Map each task to the skills needed to complete it. This enables delegation to sp
|
|
|
121
146
|
- Every task must have at least one acceptance criterion that can be empirically verified
|
|
122
147
|
- Do not create tasks that cannot be verified -- if you cannot define how to prove it is done, the task is not well-scoped
|
|
123
148
|
- Every Task / Bug / Sub-task / Improvement is scoped to exactly one repo -- if the work spans repos, split into per-repo work units under a shared parent Story (see step 1.5)
|
|
149
|
+
- Any task proposing a new material dependency names its trust class, states that class's required evidence and whether human ratification is needed, and updates `.lisa/DEPENDENCY_DECISIONS.md` in the same change (see step 4.5) -- a proposed material dependency with no named class is not ready to build
|
|
124
150
|
- Keep tasks ordered so that no task references work that has not been completed by a prior task
|
|
125
151
|
- Flag any task that requires access, permissions, or external input not yet available
|
|
126
152
|
- Prefer more small tasks over fewer large tasks -- smaller tasks are easier to verify and less risky to fail
|
package/ui/index.html
CHANGED
|
@@ -1522,68 +1522,65 @@
|
|
|
1522
1522
|
card: "Required",
|
|
1523
1523
|
items: [
|
|
1524
1524
|
{
|
|
1525
|
+
id: "setup.install",
|
|
1525
1526
|
label: "Install Lisa and apply templates",
|
|
1526
1527
|
desc: "Detects the project’s stacks, applies project-owned templates, agent surfaces, and git hooks. External plugin/runtime installation is reported separately and never inferred from project files.",
|
|
1527
1528
|
command: "bun add -d @codyswann/lisa && bunx lisa",
|
|
1528
|
-
done: true,
|
|
1529
1529
|
},
|
|
1530
1530
|
{
|
|
1531
|
+
id: "setup.sync",
|
|
1531
1532
|
label: "Populate configuration",
|
|
1532
1533
|
desc: "Fills every missing .lisa.config.json setting (absorbing existing artifact values first) and syncs mirrored files. No unset configs.",
|
|
1533
1534
|
command: "lisa sync",
|
|
1534
|
-
done: true,
|
|
1535
1535
|
},
|
|
1536
1536
|
{
|
|
1537
|
+
id: "setup.agent-ready",
|
|
1537
1538
|
label: "Make the project agent-ready (brownfield)",
|
|
1538
1539
|
desc: "Builds the knowledge wiki through read-only, redacted ingestion; records every source as complete, partial, or unavailable; and writes wiki/gaps.md. Answer inline, re-run in a new session, repeat until every source is complete and zero gaps remain. Greenfield projects are ready by construction.",
|
|
1539
1540
|
command: "/lisa:agent-ready",
|
|
1540
|
-
done: false,
|
|
1541
|
-
why: "wiki/gaps.md has 2 open gaps",
|
|
1542
1541
|
},
|
|
1543
1542
|
{
|
|
1543
|
+
id: "setup.standards",
|
|
1544
1544
|
label: "Adopt the standards (conformance refactor)",
|
|
1545
1545
|
desc: "Apply Lisa's full lint rules, guardrails, and thresholds — the project goes red by design — then agents refactor to automated conformance without changing business logic. Empirical product verification remains a separate Verify-factory gate.",
|
|
1546
1546
|
command:
|
|
1547
1547
|
"/lisa:improve:* · /lisa:fix:linter-error · lisa standards-proof",
|
|
1548
|
-
done: false,
|
|
1549
|
-
why: "blocked by agent-ready",
|
|
1550
1548
|
},
|
|
1551
1549
|
{
|
|
1550
|
+
id: "setup.tracker",
|
|
1552
1551
|
label: "Connect the work tracker",
|
|
1553
1552
|
desc: "Verifies the workflow status names and writes the tracker section. This project: JIRA, project ACME.",
|
|
1554
1553
|
command: "/lisa:setup:jira | github | linear",
|
|
1555
|
-
done: true,
|
|
1556
1554
|
},
|
|
1557
1555
|
{
|
|
1556
|
+
id: "setup.prd-source",
|
|
1558
1557
|
label: "Connect the PRD source",
|
|
1559
1558
|
desc: "Wires the product-requirements queue and its lifecycle vocabulary. This project: Notion.",
|
|
1560
1559
|
command: "/lisa:setup:notion | confluence | linear | github",
|
|
1561
|
-
done: true,
|
|
1562
1560
|
},
|
|
1563
1561
|
{
|
|
1562
|
+
id: "setup.github-governance",
|
|
1564
1563
|
label: "Apply GitHub repository governance",
|
|
1565
1564
|
desc: "Repo settings (merge-only), rulesets with required checks, write deploy key, deployment environments with approval gates.",
|
|
1566
1565
|
command: "/lisa:setup:github-repo",
|
|
1567
|
-
done: true,
|
|
1568
1566
|
},
|
|
1569
1567
|
{
|
|
1568
|
+
id: "setup.secrets",
|
|
1570
1569
|
label: "Provision CI secrets",
|
|
1571
1570
|
desc: "CLAUDE_CODE_OAUTH_TOKEN, GITGUARDIAN_API_KEY, SONAR_TOKEN, per-environment AWS accounts, and the optional scanners.",
|
|
1572
1571
|
command: "gh secret set …",
|
|
1573
|
-
done: false,
|
|
1574
|
-
why: "2 missing: SNYK_TOKEN, FOSSA_API_KEY",
|
|
1575
1572
|
},
|
|
1576
1573
|
{
|
|
1574
|
+
id: "setup.automations",
|
|
1577
1575
|
label: "Schedule the automations",
|
|
1578
1576
|
desc: "Creates the six-automation fleet — intake, repair, and the QA / Product Planning / Monitoring loops — on the harness’s native scheduler.",
|
|
1579
1577
|
command: "/lisa:setup-automations",
|
|
1580
|
-
done: false,
|
|
1581
1578
|
},
|
|
1582
1579
|
{
|
|
1580
|
+
id: "setup.exploration",
|
|
1583
1581
|
label: "Configure exploration environments",
|
|
1584
1582
|
desc: "Per-environment mutation policy and test identity so agents can use the product safely (production defaults to forbidden).",
|
|
1585
1583
|
command: ".lisa.config.json exploration.*",
|
|
1586
|
-
done: false,
|
|
1587
1584
|
},
|
|
1588
1585
|
],
|
|
1589
1586
|
},
|
|
@@ -1592,17 +1589,17 @@
|
|
|
1592
1589
|
card: "Optional",
|
|
1593
1590
|
items: [
|
|
1594
1591
|
{
|
|
1592
|
+
id: "setup.wiki",
|
|
1595
1593
|
label: "Install the LLM wiki",
|
|
1596
1594
|
desc: "In-repo knowledge base agents read and maintain.",
|
|
1597
1595
|
command: "/lisa:wiki:install",
|
|
1598
|
-
done: false,
|
|
1599
1596
|
optional: true,
|
|
1600
1597
|
},
|
|
1601
1598
|
{
|
|
1599
|
+
id: "setup.starter-provenance",
|
|
1602
1600
|
label: "Record starter provenance",
|
|
1603
1601
|
desc: "Which starter repo(s) this project descends from, enabling starter sync (planned).",
|
|
1604
1602
|
command: ".lisa.config.json starter.*",
|
|
1605
|
-
done: false,
|
|
1606
1603
|
optional: true,
|
|
1607
1604
|
},
|
|
1608
1605
|
],
|
|
@@ -5085,6 +5082,30 @@
|
|
|
5085
5082
|
let healthChipState = { state: "idle" };
|
|
5086
5083
|
/* Durable Health view model projected by every whole-page render. */
|
|
5087
5084
|
let healthViewState = { state: "idle" };
|
|
5085
|
+
const SETUP_READINESS_CHECKS = [
|
|
5086
|
+
"setup.install",
|
|
5087
|
+
"setup.sync",
|
|
5088
|
+
"setup.agent-ready",
|
|
5089
|
+
"setup.standards",
|
|
5090
|
+
"setup.tracker",
|
|
5091
|
+
"setup.prd-source",
|
|
5092
|
+
"setup.github-governance",
|
|
5093
|
+
"setup.secrets",
|
|
5094
|
+
"setup.automations",
|
|
5095
|
+
"setup.exploration",
|
|
5096
|
+
"setup.wiki",
|
|
5097
|
+
"setup.starter-provenance",
|
|
5098
|
+
];
|
|
5099
|
+
const SETUP_READINESS_UNAVAILABLE =
|
|
5100
|
+
"Setup readiness is unavailable. Re-open the console after checking the local Lisa service.";
|
|
5101
|
+
/* Durable Setup state survives every whole-page live-status re-render. */
|
|
5102
|
+
let setupReadinessState = {
|
|
5103
|
+
state: "loading",
|
|
5104
|
+
findings: new Map(),
|
|
5105
|
+
message: "Checking current setup readiness.",
|
|
5106
|
+
};
|
|
5107
|
+
let setupReadinessGeneration = 0;
|
|
5108
|
+
let setupReadinessInFlight = null;
|
|
5088
5109
|
|
|
5089
5110
|
function el(tag, cls, html) {
|
|
5090
5111
|
const node = document.createElement(tag);
|
|
@@ -5711,6 +5732,7 @@
|
|
|
5711
5732
|
|
|
5712
5733
|
function buildChecklist(block) {
|
|
5713
5734
|
const card = el("div", "card");
|
|
5735
|
+
card.dataset.setupChecklist = block.card;
|
|
5714
5736
|
const head = el("div", "card-head");
|
|
5715
5737
|
const note = el("span", "note");
|
|
5716
5738
|
const countDone = () =>
|
|
@@ -5724,35 +5746,38 @@
|
|
|
5724
5746
|
card.appendChild(head);
|
|
5725
5747
|
const body = el("div", "card-body");
|
|
5726
5748
|
block.items.forEach(item => {
|
|
5727
|
-
const
|
|
5749
|
+
const finding = setupReadinessState.findings.get(item.id);
|
|
5750
|
+
const isDone = finding && finding.status === "pass";
|
|
5751
|
+
const reason =
|
|
5752
|
+
setupReadinessState.state === "result" && finding
|
|
5753
|
+
? finding.reason
|
|
5754
|
+
: setupReadinessState.message;
|
|
5755
|
+
const row = el("div", "check-item" + (isDone ? " done" : ""));
|
|
5756
|
+
row.dataset.setupCheck = item.id;
|
|
5728
5757
|
const right = el("div", "check-right");
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
)
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
el(
|
|
5745
|
-
"span",
|
|
5746
|
-
"status-why",
|
|
5747
|
-
"read-only: setup checklist state has not shipped yet"
|
|
5748
|
-
)
|
|
5749
|
-
);
|
|
5750
|
-
};
|
|
5758
|
+
right.appendChild(
|
|
5759
|
+
el(
|
|
5760
|
+
"span",
|
|
5761
|
+
"badge " +
|
|
5762
|
+
(isDone
|
|
5763
|
+
? "pass"
|
|
5764
|
+
: finding?.status === "fail"
|
|
5765
|
+
? "fail"
|
|
5766
|
+
: "warn"),
|
|
5767
|
+
isDone ? "done" : "pending"
|
|
5768
|
+
)
|
|
5769
|
+
);
|
|
5770
|
+
if (!isDone) {
|
|
5771
|
+
right.appendChild(el("span", "status-why", esc(reason)));
|
|
5772
|
+
}
|
|
5751
5773
|
const ck = el("button", "ck");
|
|
5752
5774
|
ck.type = "button";
|
|
5753
5775
|
ck.disabled = true;
|
|
5754
|
-
ck.title =
|
|
5755
|
-
ck.setAttribute(
|
|
5776
|
+
ck.title = reason;
|
|
5777
|
+
ck.setAttribute(
|
|
5778
|
+
"aria-label",
|
|
5779
|
+
item.label + ": " + (isDone ? "done" : "pending") + ". " + reason
|
|
5780
|
+
);
|
|
5756
5781
|
row.appendChild(ck);
|
|
5757
5782
|
const content = el("div", "check-content");
|
|
5758
5783
|
const lab = el("div", "check-label", esc(item.label));
|
|
@@ -5765,7 +5790,6 @@
|
|
|
5765
5790
|
content.appendChild(el("span", "keychip", esc(item.command)));
|
|
5766
5791
|
}
|
|
5767
5792
|
row.appendChild(content);
|
|
5768
|
-
refreshRight();
|
|
5769
5793
|
row.appendChild(right);
|
|
5770
5794
|
body.appendChild(row);
|
|
5771
5795
|
});
|
|
@@ -5947,6 +5971,7 @@
|
|
|
5947
5971
|
|
|
5948
5972
|
let activeSection = "overview";
|
|
5949
5973
|
function showSection(sid) {
|
|
5974
|
+
const previousSection = activeSection;
|
|
5950
5975
|
activeSection = sid;
|
|
5951
5976
|
document
|
|
5952
5977
|
.querySelectorAll(".section")
|
|
@@ -5962,6 +5987,11 @@
|
|
|
5962
5987
|
history.replaceState(null, "", "#" + sid);
|
|
5963
5988
|
applyFilter(document.getElementById("search").value);
|
|
5964
5989
|
window.scrollTo({ top: 0 });
|
|
5990
|
+
if (sid === "setup" && previousSection !== "setup") {
|
|
5991
|
+
void hydrateSetupReadiness({
|
|
5992
|
+
refresh: setupReadinessGeneration > 0,
|
|
5993
|
+
});
|
|
5994
|
+
}
|
|
5965
5995
|
}
|
|
5966
5996
|
|
|
5967
5997
|
function applyFilter(query) {
|
|
@@ -6677,6 +6707,128 @@
|
|
|
6677
6707
|
}
|
|
6678
6708
|
}
|
|
6679
6709
|
|
|
6710
|
+
/** Validate the strict three-field Setup readiness transport contract. */
|
|
6711
|
+
function requireSetupReadinessResult(candidate) {
|
|
6712
|
+
const isObject = value =>
|
|
6713
|
+
value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6714
|
+
const hasExactKeys = (value, keys) =>
|
|
6715
|
+
isObject(value) &&
|
|
6716
|
+
Object.keys(value).sort().join(",") === [...keys].sort().join(",");
|
|
6717
|
+
const canonicalUtc = value => {
|
|
6718
|
+
if (
|
|
6719
|
+
typeof value !== "string" ||
|
|
6720
|
+
!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value)
|
|
6721
|
+
) {
|
|
6722
|
+
return false;
|
|
6723
|
+
}
|
|
6724
|
+
const instant = new Date(value);
|
|
6725
|
+
return (
|
|
6726
|
+
!Number.isNaN(instant.valueOf()) && instant.toISOString() === value
|
|
6727
|
+
);
|
|
6728
|
+
};
|
|
6729
|
+
const readableReason = value =>
|
|
6730
|
+
typeof value === "string" &&
|
|
6731
|
+
value.trim() === value &&
|
|
6732
|
+
value.length > 0 &&
|
|
6733
|
+
new TextEncoder().encode(value).length <= 2000 &&
|
|
6734
|
+
!Array.from(value).some(character => {
|
|
6735
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
6736
|
+
return (
|
|
6737
|
+
codePoint <= 0x1f ||
|
|
6738
|
+
(codePoint >= 0x7f && codePoint <= 0x9f) ||
|
|
6739
|
+
(codePoint >= 0x202a && codePoint <= 0x202e) ||
|
|
6740
|
+
(codePoint >= 0x2066 && codePoint <= 0x2069)
|
|
6741
|
+
);
|
|
6742
|
+
});
|
|
6743
|
+
if (
|
|
6744
|
+
!hasExactKeys(candidate, [
|
|
6745
|
+
"schemaVersion",
|
|
6746
|
+
"observedAt",
|
|
6747
|
+
"findings",
|
|
6748
|
+
]) ||
|
|
6749
|
+
candidate.schemaVersion !== 1 ||
|
|
6750
|
+
!canonicalUtc(candidate.observedAt) ||
|
|
6751
|
+
!Array.isArray(candidate.findings) ||
|
|
6752
|
+
candidate.findings.length !== SETUP_READINESS_CHECKS.length
|
|
6753
|
+
) {
|
|
6754
|
+
throw new TypeError(
|
|
6755
|
+
"Setup readiness response is not valid schema v1 JSON"
|
|
6756
|
+
);
|
|
6757
|
+
}
|
|
6758
|
+
const findings = new Map();
|
|
6759
|
+
candidate.findings.forEach((finding, index) => {
|
|
6760
|
+
if (
|
|
6761
|
+
!hasExactKeys(finding, ["check", "layer", "status", "reason"]) ||
|
|
6762
|
+
finding.check !== SETUP_READINESS_CHECKS[index] ||
|
|
6763
|
+
finding.layer !== "deterministic" ||
|
|
6764
|
+
!["pass", "warn", "fail"].includes(finding.status) ||
|
|
6765
|
+
!readableReason(finding.reason)
|
|
6766
|
+
) {
|
|
6767
|
+
throw new TypeError(
|
|
6768
|
+
"Setup readiness response contains an invalid finding"
|
|
6769
|
+
);
|
|
6770
|
+
}
|
|
6771
|
+
findings.set(finding.check, finding);
|
|
6772
|
+
});
|
|
6773
|
+
return findings;
|
|
6774
|
+
}
|
|
6775
|
+
|
|
6776
|
+
/** Rebuild only the two Setup checklist cards from durable readiness state. */
|
|
6777
|
+
function repaintSetupChecklist() {
|
|
6778
|
+
const section = document.getElementById("section-setup");
|
|
6779
|
+
if (!section) return;
|
|
6780
|
+
const blocks = DATA.sections.setup.blocks.filter(
|
|
6781
|
+
block => block.type === "checklist"
|
|
6782
|
+
);
|
|
6783
|
+
const cards = section.querySelectorAll("[data-setup-checklist]");
|
|
6784
|
+
blocks.forEach((block, index) => {
|
|
6785
|
+
if (cards[index]) cards[index].replaceWith(buildChecklist(block));
|
|
6786
|
+
});
|
|
6787
|
+
}
|
|
6788
|
+
|
|
6789
|
+
/** Read current Setup readiness with same-entry dedupe and stale-response protection. */
|
|
6790
|
+
function hydrateSetupReadiness({ refresh = false } = {}) {
|
|
6791
|
+
if (!refresh && setupReadinessInFlight) {
|
|
6792
|
+
return setupReadinessInFlight;
|
|
6793
|
+
}
|
|
6794
|
+
setupReadinessState = {
|
|
6795
|
+
state: "loading",
|
|
6796
|
+
findings: new Map(),
|
|
6797
|
+
message: "Checking current setup readiness.",
|
|
6798
|
+
};
|
|
6799
|
+
repaintSetupChecklist();
|
|
6800
|
+
const generation = ++setupReadinessGeneration;
|
|
6801
|
+
const request = (async () => {
|
|
6802
|
+
let nextState;
|
|
6803
|
+
try {
|
|
6804
|
+
const response = await fetch("/api/setup-readiness", {
|
|
6805
|
+
cache: "no-store",
|
|
6806
|
+
});
|
|
6807
|
+
if (!response.ok) throw new Error(SETUP_READINESS_UNAVAILABLE);
|
|
6808
|
+
nextState = {
|
|
6809
|
+
state: "result",
|
|
6810
|
+
findings: requireSetupReadinessResult(await response.json()),
|
|
6811
|
+
message: "",
|
|
6812
|
+
};
|
|
6813
|
+
} catch {
|
|
6814
|
+
nextState = {
|
|
6815
|
+
state: "error",
|
|
6816
|
+
findings: new Map(),
|
|
6817
|
+
message: SETUP_READINESS_UNAVAILABLE,
|
|
6818
|
+
};
|
|
6819
|
+
}
|
|
6820
|
+
if (generation === setupReadinessGeneration) {
|
|
6821
|
+
setupReadinessState = nextState;
|
|
6822
|
+
repaintSetupChecklist();
|
|
6823
|
+
}
|
|
6824
|
+
if (setupReadinessInFlight === request) {
|
|
6825
|
+
setupReadinessInFlight = null;
|
|
6826
|
+
}
|
|
6827
|
+
})();
|
|
6828
|
+
setupReadinessInFlight = request;
|
|
6829
|
+
return request;
|
|
6830
|
+
}
|
|
6831
|
+
|
|
6680
6832
|
/** Run exactly one deterministic Health v1 check through the local server. */
|
|
6681
6833
|
async function runHealthCheck() {
|
|
6682
6834
|
const button = document.getElementById("runHealthCheckButton");
|
|
@@ -7224,11 +7376,11 @@
|
|
|
7224
7376
|
function boot() {
|
|
7225
7377
|
hydrateFromLiveConfig();
|
|
7226
7378
|
renderAll();
|
|
7227
|
-
void hydrateLiveStatuses();
|
|
7228
|
-
void hydrateHealth();
|
|
7229
7379
|
showSection(location.hash ? location.hash.slice(1) : "overview");
|
|
7230
7380
|
if (!document.getElementById("section-" + activeSection))
|
|
7231
7381
|
showSection("overview");
|
|
7382
|
+
void hydrateLiveStatuses();
|
|
7383
|
+
void hydrateHealth();
|
|
7232
7384
|
}
|
|
7233
7385
|
if (document.readyState === "loading") {
|
|
7234
7386
|
document.addEventListener("DOMContentLoaded", boot);
|