@codyswann/lisa 2.239.0 → 2.240.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/dist/core/learnings-entry.d.ts +9 -0
- package/dist/core/learnings-entry.d.ts.map +1 -1
- package/dist/core/learnings-entry.js +4 -2
- package/dist/core/learnings-entry.js.map +1 -1
- package/dist/core/learnings-writer.d.ts +33 -0
- package/dist/core/learnings-writer.d.ts.map +1 -1
- package/dist/core/learnings-writer.js +75 -1
- package/dist/core/learnings-writer.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-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-attribute-failure/agents/openai.yaml +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +61 -8
- package/plugins/lisa/commands/attribute-failure.md +6 -0
- package/plugins/lisa/commands/persist-learning.md +1 -1
- package/plugins/lisa/rules/reference/project-learnings.md +18 -0
- package/plugins/lisa/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa/skills/lisa-attribute-failure/agents/openai.yaml +4 -0
- package/plugins/lisa/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +62 -9
- package/plugins/lisa-agy/commands/lisa/attribute-failure.md +6 -0
- package/plugins/lisa-agy/commands/lisa/persist-learning.md +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +62 -9
- 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/commands/lisa/attribute-failure.md +6 -0
- package/plugins/lisa-copilot/commands/lisa/persist-learning.md +1 -1
- package/plugins/lisa-copilot/rules/reference/project-learnings.md +18 -0
- package/plugins/lisa-copilot/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +62 -9
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/commands/lisa/attribute-failure.md +6 -0
- package/plugins/lisa-cursor/commands/lisa/persist-learning.md +1 -1
- package/plugins/lisa-cursor/rules/project-learnings-reference.mdc +18 -0
- package/plugins/lisa-cursor/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +62 -9
- 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/commands/attribute-failure.md +6 -0
- package/plugins/src/base/commands/persist-learning.md +1 -1
- package/plugins/src/base/rules/reference/project-learnings.md +18 -0
- package/plugins/src/base/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/src/base/skills/lisa-doctor/SKILL.md +28 -77
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +16 -0
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +16 -0
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +16 -0
- package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +62 -9
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lisa-attribute-failure
|
|
3
|
+
description: "Event-triggered root-cause attribution for an arbitrary failure: decide, with cited evidence, whether the defect is Lisa's fault or the project's. Accepts a failure event (defect description, implicated files, rule/skill/hook in play) and returns a verdict of lisa | project | ambiguous plus the evidence relied on. Read-only — it never files, writes, or remediates; callers (lisa-doctor findings, the learning judgment gate, rework triage) consume the verdict. Extracted from lisa-doctor's upstream Lisa change-history diagnosis (#1494) so the same attribution procedure can run on ANY failure event, not only doctor config-audit findings."
|
|
4
|
+
allowed-tools: ["Skill", "Bash", "Read", "Glob", "Grep"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Attribute Failure
|
|
8
|
+
|
|
9
|
+
Attribute ONE failure event to Lisa or the project, with cited evidence. Failure event: $ARGUMENTS
|
|
10
|
+
|
|
11
|
+
Before a Lisa-caused failure can be routed upstream, something has to say — with evidence — "this was Lisa's fault, not the project's." A failure has two possible causes: the project drifted, or **Lisa itself changed or shipped the defect**. This skill must distinguish them instead of blaming the project by default, and equally must never blame Lisa without conclusive evidence. Wrong attribution in either direction is the failure mode; **inconclusive evidence is always `ambiguous`, and ambiguous stays local and low-confidence — never upstream.**
|
|
12
|
+
|
|
13
|
+
## Input — the failure event
|
|
14
|
+
|
|
15
|
+
Accept the event as JSON or `key=value` fields. This procedure is **event-triggered, not version-window-keyed**: any failure can be attributed, not only a doctor config-audit finding.
|
|
16
|
+
|
|
17
|
+
- `defect` — what went wrong, in plain language (required)
|
|
18
|
+
- `implicated_files` — the file paths where the defect lives or manifests (required when known)
|
|
19
|
+
- `surface_in_play` — the Lisa rule / skill / hook / template / workflow involved, if any
|
|
20
|
+
- `installed_version` / `latest_version` — the Lisa version window, when the caller knows it; otherwise resolve it as signal 3 describes
|
|
21
|
+
- `failure_class` — a short slug naming the class of failure (used by downstream filing for the root-cause key)
|
|
22
|
+
|
|
23
|
+
## Output — the verdict
|
|
24
|
+
|
|
25
|
+
Return exactly one verdict — `lisa` | `project` | `ambiguous` — plus the evidence it relied on:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
## Attribution: [lisa | project | ambiguous]
|
|
29
|
+
|
|
30
|
+
**Signal:** [managed-surface | shipped-artifact-behavior | upstream-history | none-conclusive]
|
|
31
|
+
**Lisa surface at fault:** [path or rule/skill/hook name | n/a]
|
|
32
|
+
**Cited evidence:**
|
|
33
|
+
- [each item names the signal it came from and the concrete citation: file path + ownership proof, shipped artifact text, or commit sha/subject/version]
|
|
34
|
+
**Confidence note:** [why the evidence is conclusive, or exactly what was inconclusive]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Verdict rules:
|
|
38
|
+
|
|
39
|
+
- **`lisa`** — at least one signal conclusively pins the defect on a Lisa-shipped surface or upstream change, and the evidence names that surface. Never emit `lisa` from degraded, truncated, or unverified history.
|
|
40
|
+
- **`project`** — the implicated files are project-owned, no shipped Lisa artifact drove the behavior, and the upstream-history window shows no relevant Lisa change. Cite the absence explicitly (which paths were checked, which window showed no relevant change).
|
|
41
|
+
- **`ambiguous`** — anything else: unresolvable version window, unreachable history, partial ownership, conflicting signals. Ambiguous is treated as local and low-confidence; nothing is escalated upstream from it.
|
|
42
|
+
|
|
43
|
+
## The three signals (evaluate in order)
|
|
44
|
+
|
|
45
|
+
### Signal 1 — the defect lives in a Lisa-managed surface
|
|
46
|
+
|
|
47
|
+
Resolve ownership of each implicated file the way doctor's config audit does:
|
|
48
|
+
|
|
49
|
+
- **Copy-overwrite / managed**: the path is populated by `lisa apply` from a stack template (`typescript/`, `expo/`, `nestjs/`, `cdk/`, `harper-fabric/`, `rails/` copy-overwrite trees), is a plugin-distributed rule/skill/hook/agent/command surface, carries Lisa governance markers or a Lisa version stamp, or is governed by `package.lisa.json` `force` keys. A defect in the shipped content of such a surface is **Lisa's fault** — any local edit would be overwritten on the next `lisa apply`.
|
|
50
|
+
- **Create-only**: the local copy is project-owned after scaffolding, but if the defect is faithful to the template as shipped, the template is still Lisa's fault (every newly scaffolded repo inherits it). Cite the template origin, and note the local copy will not be overwritten.
|
|
51
|
+
- **Project-owned**: not from a Lisa template and not Lisa-managed — signal 1 is negative; continue.
|
|
52
|
+
|
|
53
|
+
If the project locally modified a managed surface and the defect lives in the local modification, that is project drift, not a Lisa defect — signal 1 is negative for `lisa` and positive evidence for `project`.
|
|
54
|
+
|
|
55
|
+
### Signal 2 — a shipped Lisa rule/skill/hook drove the wrong behavior
|
|
56
|
+
|
|
57
|
+
Read the shipped artifact named in `surface_in_play` (the plugin-distributed rule, skill, hook, agent, or CI workflow as Lisa ships it — not a local fork). If following its instructions or configuration as shipped produces the observed defect, the verdict is `lisa`: cite the artifact path and the specific shipped text or configuration that drove the behavior. If the artifact is shipped correct and was misapplied locally, that is evidence for `project`.
|
|
58
|
+
|
|
59
|
+
### Signal 3 — the upstream-history window shows Lisa changed the relevant contract
|
|
60
|
+
|
|
61
|
+
This is the #1494 doctor procedure, unchanged in behavior — here it is the third signal, not the trigger. Whenever signals 1-2 are not conclusive on their own — and always before a definitive `project` verdict — pull Lisa's own git history for the version window and read what actually changed:
|
|
62
|
+
|
|
63
|
+
1. **Resolve the version window.** Use the caller-supplied `installed_version`/`latest_version` when present; otherwise determine the project's installed Lisa version (the `@codyswann/lisa` entry in `package.json`/lockfile, or the plugin version stamp on the active runtime) and the latest published version (`npm view @codyswann/lisa version`, or the update check's cached result). An unresolvable window makes this signal inconclusive — it can support `ambiguous`, never `lisa`.
|
|
64
|
+
2. **Pull the upstream history for that window** (read-only; no clone required when `gh` is available):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
gh api "repos/CodySwannGT/lisa/compare/v<installed>...v<latest>" \
|
|
68
|
+
--paginate --slurp |
|
|
69
|
+
jq '{total_commits: .[0].total_commits, files: [.[0].files[]?.filename], commits: [.[].commits[]? | {sha, subject: (.commit.message | split("\n")[0]), api_url: .url, html_url, parents: [.parents[]?.sha]}]}'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`--paginate` fetches every page of commits, and `--slurp` gathers those pages into a single
|
|
73
|
+
array before the external `jq` projection runs. GitHub CLI does not permit its built-in `--jq`
|
|
74
|
+
flag together with `--slurp`, so keep the pipe as shown; without `--slurp`, paginated responses
|
|
75
|
+
are not one merged input. `total_commits` and `files` only need the first page
|
|
76
|
+
(files are capped at 300 and not repeated on later pages); `commits` flattens across all pages
|
|
77
|
+
while retaining each commit SHA and URLs needed for accurate follow-up.
|
|
78
|
+
|
|
79
|
+
After path-scoping identifies a candidate commit, fetch its targeted file-level diff context by
|
|
80
|
+
the retained SHA rather than attributing from the subject alone:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
gh api "repos/CodySwannGT/lisa/commits/<sha>" \
|
|
84
|
+
--jq '{sha, files: [.files[]? | select(.filename == "<relevant-path>" or (.filename | startswith("<relevant-prefix>/"))) | {filename, status, additions, deletions, changes, patch}]}'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Preserve the returned filename, status, counts, and available patch with the SHA in the
|
|
88
|
+
upstream-history projection. A missing or truncated `patch` is not proof of no relevant change;
|
|
89
|
+
use the compare diff fallback below or downgrade the attribution to `ambiguous` when
|
|
90
|
+
commit-level context cannot be established.
|
|
91
|
+
|
|
92
|
+
The compare endpoint paginates commits (250 without `--paginate`) and only lists changed files
|
|
93
|
+
on the first page, capped at 300 total — a large version window can silently drop commits or
|
|
94
|
+
files. If `total_commits` or the file count looks truncated, re-run with the
|
|
95
|
+
`application/vnd.github.diff` accept header (`gh api ... -H "Accept: application/vnd.github.diff"`)
|
|
96
|
+
to pull the full patch text, or fall back to the bounded-fetch `git log` below. When completeness
|
|
97
|
+
still can't be established, say so in the evidence and return `ambiguous` rather than attributing
|
|
98
|
+
with unverified confidence.
|
|
99
|
+
|
|
100
|
+
Fallbacks, in order: `gh api repos/CodySwannGT/lisa/commits?path=<template-path>` for a
|
|
101
|
+
path-scoped view — note this endpoint has no way to bound results to the `v<installed>..v<latest>`
|
|
102
|
+
window, so treat its output as best-effort context only, not authoritative attribution; a
|
|
103
|
+
finite-depth, explicit-tag fetch, which is bounded to the two version refs and should be preferred
|
|
104
|
+
for definitive attribution; or the local marketplace/plugin cache checkout when the runtime has
|
|
105
|
+
one. For the fetch fallback, use a temporary directory and a fixed history ceiling:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
lisa_history_dir="$(mktemp -d)"
|
|
109
|
+
git init "$lisa_history_dir"
|
|
110
|
+
git -C "$lisa_history_dir" remote add origin https://github.com/CodySwannGT/lisa.git
|
|
111
|
+
git -C "$lisa_history_dir" fetch --no-tags --filter=blob:none --depth=256 origin \
|
|
112
|
+
refs/tags/v<installed>:refs/tags/v<installed> \
|
|
113
|
+
refs/tags/v<latest>:refs/tags/v<latest>
|
|
114
|
+
git -C "$lisa_history_dir" merge-base --is-ancestor v<installed> v<latest>
|
|
115
|
+
git -C "$lisa_history_dir" log --format='%H%x09%s' v<installed>..v<latest> -- <paths>
|
|
116
|
+
git -C "$lisa_history_dir" show --format=fuller --stat --patch <relevant-sha> -- <paths>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The explicit tag refspecs, `--no-tags`, and finite `--depth=256` make this fetch bounded. Do not
|
|
120
|
+
silently deepen beyond that ceiling. If `merge-base --is-ancestor` fails, the shallow window is
|
|
121
|
+
incomplete (or the tags are not on one ancestry line): do not make definitive attribution from
|
|
122
|
+
it. If none of the bounded sources are reachable, or only the unbounded path-scoped fallback is
|
|
123
|
+
reachable, report the gap in the evidence and return `ambiguous` — never fail the caller's flow
|
|
124
|
+
because history was unavailable or incomplete, and never let a degraded history produce `lisa`.
|
|
125
|
+
3. **Scope the reading to what the failure touches.** Filter the commit list to the paths that
|
|
126
|
+
generate the failing surface: the detected stacks' template dirs (`typescript/`, `expo/`, …),
|
|
127
|
+
`plugins/src/base/` for skills/hooks/rules, `scripts/` for governance scripts, and the shipped
|
|
128
|
+
config factories (`src/configs/`). A failure about a lint rule reads the lint-config commits,
|
|
129
|
+
not the whole log.
|
|
130
|
+
4. **Attribute.** When the upstream history shows Lisa changed the relevant contract (a tightened
|
|
131
|
+
lint rule, a renamed check context, a new required config key), the verdict is `lisa` — cite the
|
|
132
|
+
commit subject/version. When history shows no relevant upstream change and signals 1-2 are also
|
|
133
|
+
negative, the project drifted — the verdict is `project`, citing the absence of a relevant
|
|
134
|
+
upstream change as the evidence.
|
|
135
|
+
|
|
136
|
+
## Rules
|
|
137
|
+
|
|
138
|
+
- **Read-only.** This skill reads the project and Lisa's repository; it never writes to either, never files issues, and never remediates. Filing the upstream ticket on a `lisa` verdict is the caller's flow (`lisa-persist-learning`, `handoff-upstream` disposition); doctor maps verdicts into its findings; remediation stays with whoever called.
|
|
139
|
+
- **Never block.** Attribution failure, missing tooling (`gh` unavailable), or degraded history degrades to `ambiguous` with the gap named in the evidence — it never raises an error that stops the caller's build or audit.
|
|
140
|
+
- **Every verdict cites its evidence.** An attribution without a named signal and concrete citation is invalid — return `ambiguous` instead. Evidence destined for upstream surfaces quotes ONLY Lisa-owned surface text (never host env values, tokens/credentials, PII, or proprietary host code — link the host issue instead of quoting it); the binding redaction procedure lives in `lisa-persist-learning`'s `handoff-upstream` step.
|
|
141
|
+
- **Ambiguous never escalates.** `ambiguous` is a terminal local verdict: low-confidence, no upstream filing, no durable local rule derived from it.
|
|
142
|
+
- **Headless-safe and idempotent**: no prompts, no side effects, same event in → same verdict out.
|
|
@@ -296,88 +296,39 @@ without turning the base doctor into a second `lisa-wiki-doctor`.
|
|
|
296
296
|
A failing or warning check has two possible causes: the project drifted, or **Lisa itself changed
|
|
297
297
|
upstream** since this project last updated. Doctor must distinguish them instead of blaming the
|
|
298
298
|
project by default. Whenever findings need explanation — and always before proposing repairs —
|
|
299
|
-
|
|
299
|
+
attribute the finding with real evidence.
|
|
300
|
+
|
|
301
|
+
The attribution procedure itself is shared: it lives in the `lisa-attribute-failure` skill
|
|
302
|
+
(extracted from this section so any failure event can be attributed, not only doctor findings).
|
|
303
|
+
Doctor invokes it per finding:
|
|
300
304
|
|
|
301
305
|
1. **Resolve the version window.** Determine the project's installed Lisa version (the
|
|
302
306
|
`@codyswann/lisa` entry in `package.json`/lockfile, or the plugin version stamp on the active
|
|
303
307
|
runtime) and the latest published version (`npm view @codyswann/lisa version`, or the update
|
|
304
308
|
check's cached result).
|
|
305
|
-
2. **
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
Preserve the returned filename, status, counts, and available patch with the SHA in the
|
|
330
|
-
upstream-history projection. A missing or truncated `patch` is not proof of no relevant change;
|
|
331
|
-
use the compare diff fallback below or downgrade attribution to `WARN` when commit-level context
|
|
332
|
-
cannot be established.
|
|
333
|
-
|
|
334
|
-
The compare endpoint paginates commits (250 without `--paginate`) and only lists changed files
|
|
335
|
-
on the first page, capped at 300 total — a large version window can silently drop commits or
|
|
336
|
-
files. If `total_commits` or the file count looks truncated, re-run with the
|
|
337
|
-
`application/vnd.github.diff` accept header (`gh api ... -H "Accept: application/vnd.github.diff"`)
|
|
338
|
-
to pull the full patch text, or fall back to the bounded-fetch `git log` below. When completeness
|
|
339
|
-
still can't be established, say so in the finding and mark it `WARN` rather than attributing
|
|
340
|
-
drift with unverified confidence.
|
|
341
|
-
|
|
342
|
-
Fallbacks, in order: `gh api repos/CodySwannGT/lisa/commits?path=<template-path>` for a
|
|
343
|
-
path-scoped view — note this endpoint has no way to bound results to the `v<installed>..v<latest>`
|
|
344
|
-
window, so treat its output as best-effort context only, not authoritative attribution; a
|
|
345
|
-
finite-depth, explicit-tag fetch, which is bounded to the two version refs and should be preferred
|
|
346
|
-
for definitive attribution; or the local marketplace/plugin cache checkout when the runtime has
|
|
347
|
-
one. For the fetch fallback, use a temporary directory and a fixed history ceiling:
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
lisa_history_dir="$(mktemp -d)"
|
|
351
|
-
git init "$lisa_history_dir"
|
|
352
|
-
git -C "$lisa_history_dir" remote add origin https://github.com/CodySwannGT/lisa.git
|
|
353
|
-
git -C "$lisa_history_dir" fetch --no-tags --filter=blob:none --depth=256 origin \
|
|
354
|
-
refs/tags/v<installed>:refs/tags/v<installed> \
|
|
355
|
-
refs/tags/v<latest>:refs/tags/v<latest>
|
|
356
|
-
git -C "$lisa_history_dir" merge-base --is-ancestor v<installed> v<latest>
|
|
357
|
-
git -C "$lisa_history_dir" log --format='%H%x09%s' v<installed>..v<latest> -- <paths>
|
|
358
|
-
git -C "$lisa_history_dir" show --format=fuller --stat --patch <relevant-sha> -- <paths>
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
The explicit tag refspecs, `--no-tags`, and finite `--depth=256` make this fetch bounded. Do not
|
|
362
|
-
silently deepen beyond that ceiling. If `merge-base --is-ancestor` fails, the shallow window is
|
|
363
|
-
incomplete (or the tags are not on one ancestry line): do not make definitive attribution from
|
|
364
|
-
it. If none of the bounded sources are reachable, or only the unbounded path-scoped fallback is
|
|
365
|
-
reachable, report the gap as a `WARN`-level observability note — never fail the audit because
|
|
366
|
-
history was unavailable or incomplete.
|
|
367
|
-
3. **Scope the reading to what the finding touches.** Filter the commit list to the paths that
|
|
368
|
-
generate the failing surface: the detected stacks' template dirs (`typescript/`, `expo/`, …),
|
|
369
|
-
`plugins/src/base/` for skills/hooks/rules, `scripts/` for governance scripts, and the shipped
|
|
370
|
-
config factories (`src/configs/`). A finding about a lint rule failure reads the lint-config
|
|
371
|
-
commits, not the whole log.
|
|
372
|
-
4. **Attribute the finding.** When the upstream history shows Lisa changed the contract (a
|
|
373
|
-
tightened lint rule, a renamed check context, a new required config key), say so in `Observed:`
|
|
374
|
-
with the commit subject/version, and let `Remediation:` point at the sanctioned adoption path
|
|
375
|
-
(e.g. `lisa update` + re-apply, a documented config opt-out) rather than hand-editing managed
|
|
376
|
-
files. When history shows no relevant upstream change, the project drifted — remediate on the
|
|
377
|
-
project side.
|
|
378
|
-
|
|
379
|
-
This history pull is part of doctor's read-only contract: it reads Lisa's repository, never writes
|
|
380
|
-
to it, and repair suggestions stay suggestions.
|
|
309
|
+
2. **Invoke `lisa-attribute-failure`** with the finding as the failure event: the defect
|
|
310
|
+
description, the implicated template/config paths, the rule/skill/hook in play, and the
|
|
311
|
+
resolved version window. The skill evaluates its three ordered signals — Lisa-managed surface
|
|
312
|
+
ownership, shipped rule/skill/hook behavior, and the upstream change-history window (the
|
|
313
|
+
version-window compare procedure formerly documented inline here, preserved verbatim in that
|
|
314
|
+
skill: pagination/`--slurp` handling, targeted per-SHA diff context, truncation caveats, and
|
|
315
|
+
the bounded explicit-tag fetch fallback) — and returns `lisa` | `project` | `ambiguous` plus
|
|
316
|
+
the cited evidence.
|
|
317
|
+
3. **Map the verdict into the finding.**
|
|
318
|
+
- `lisa` — Lisa changed the contract (a tightened lint rule, a renamed check context, a new
|
|
319
|
+
required config key) or shipped the defective surface. Say so in `Observed:` with the cited
|
|
320
|
+
evidence (commit subject/version or managed-surface proof), and let `Remediation:` point at
|
|
321
|
+
the sanctioned adoption path (e.g. `lisa update` + re-apply, a documented config opt-out)
|
|
322
|
+
rather than hand-editing managed files.
|
|
323
|
+
- `project` — history shows no relevant upstream change and the surface is project-owned: the
|
|
324
|
+
project drifted, so remediate on the project side.
|
|
325
|
+
- `ambiguous` — history was unavailable, truncated, or otherwise inconclusive: report the gap
|
|
326
|
+
as a `WARN`-level observability note with the evidence gap named — never fail the audit
|
|
327
|
+
because history was unavailable or incomplete, and never attribute drift with unverified
|
|
328
|
+
confidence.
|
|
329
|
+
|
|
330
|
+
This diagnosis remains part of doctor's read-only contract: the attribution skill reads Lisa's
|
|
331
|
+
repository, never writes to it, and repair suggestions stay suggestions.
|
|
381
332
|
|
|
382
333
|
## Output contract
|
|
383
334
|
|
|
@@ -325,6 +325,22 @@ If the canonical fix is merged but not yet present on the production branch, app
|
|
|
325
325
|
|
|
326
326
|
This path is distinct from `BLOCKED`: ambiguity, open blockers, and duplicate-of-open findings remain held for human action and must not be auto-closed.
|
|
327
327
|
|
|
328
|
+
#### 3c.2 Confirm applied learnings (last_confirmed bump)
|
|
329
|
+
|
|
330
|
+
Run this at the end of 3c, after the lifecycle outcome is recorded and before 3d. It keeps the decay pass safe: a genuinely useful learning that keeps applying stays fresh, while dead weight ages out.
|
|
331
|
+
|
|
332
|
+
1. **Identify which learnings demonstrably applied.** Resolve the learnings surface with `resolveProjectLearningsFile` and parse it with `parseLearningsFile` from `@codyswann/lisa/learnings` (never hardcode the path; a missing file skips this step silently). An entry counts as applied ONLY when its rule was explicitly cited or observably followed in this claim's plan, diff, or review responses — the plan quotes the rule or its id, or the diff does specifically what the rule mandates where the default behavior would have differed. **Presence in context is NOT application**: the ledger is loaded eagerly into every session, so counting "it was loaded" would confirm every entry on every claim and defeat decay entirely. A run that produced no plan or diff has nothing to confirm.
|
|
333
|
+
2. **Bump each applied entry exactly once** via the surgical writer:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
node -e 'import("@codyswann/lisa/learnings").then(async m => { const r = await m.confirmLearningEntry(process.cwd(), process.argv[1], new Date().toISOString().slice(0, 10)); console.log(JSON.stringify(r)); }).catch(error => { console.log(JSON.stringify({ status: "error", id: process.argv[1], message: String(error) })); })' <entry-id> || true
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The invocation is failure-safe by construction: a rejected import or write resolves to a structured `error` result instead of a crash, and the trailing `|| true` absorbs any remaining non-zero exit (missing `node`, unresolvable package). Record an `error` or non-zero outcome in the cycle summary and continue — the bump must never abort the lifecycle.
|
|
340
|
+
|
|
341
|
+
`confirmLearningEntry` advances ONLY `last_confirmed` — rule text, why, provenance, `first_learned`, and confidence are untouched — and is idempotent within a claim: a repeat same-date bump returns `unchanged`, so an entry that applied repeatedly during one claim is bumped once, not once per application.
|
|
342
|
+
3. **Never block on it.** A failed bump, an unwritable file, or a `not-found` result (the entry was pruned) is recorded under the cycle summary and the claim proceeds — shipping the issue always outranks confirming a learning about it.
|
|
343
|
+
|
|
328
344
|
#### 3d. Transition to $DONE (only after the PR is merged)
|
|
329
345
|
|
|
330
346
|
A `done` env state (`status:on-dev`, `status:on-stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Relabeling an issue `status:on-stg` on an open PR makes it *claim* a deploy that never happened. Transition only after confirming the PR merged.
|
|
@@ -257,6 +257,22 @@ If the canonical fix is merged but not yet present on the production branch, app
|
|
|
257
257
|
|
|
258
258
|
This path is distinct from `BLOCKED`: ambiguity, open blockers, and duplicate-of-open findings remain held for human action and must not be auto-closed.
|
|
259
259
|
|
|
260
|
+
#### 3c.2 Confirm applied learnings (last_confirmed bump)
|
|
261
|
+
|
|
262
|
+
Run this at the end of 3c, after the lifecycle outcome is recorded and before 3d. It keeps the decay pass safe: a genuinely useful learning that keeps applying stays fresh, while dead weight ages out.
|
|
263
|
+
|
|
264
|
+
1. **Identify which learnings demonstrably applied.** Resolve the learnings surface with `resolveProjectLearningsFile` and parse it with `parseLearningsFile` from `@codyswann/lisa/learnings` (never hardcode the path; a missing file skips this step silently). An entry counts as applied ONLY when its rule was explicitly cited or observably followed in this claim's plan, diff, or review responses — the plan quotes the rule or its id, or the diff does specifically what the rule mandates where the default behavior would have differed. **Presence in context is NOT application**: the ledger is loaded eagerly into every session, so counting "it was loaded" would confirm every entry on every claim and defeat decay entirely. A run that produced no plan or diff has nothing to confirm.
|
|
265
|
+
2. **Bump each applied entry exactly once** via the surgical writer:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
node -e 'import("@codyswann/lisa/learnings").then(async m => { const r = await m.confirmLearningEntry(process.cwd(), process.argv[1], new Date().toISOString().slice(0, 10)); console.log(JSON.stringify(r)); }).catch(error => { console.log(JSON.stringify({ status: "error", id: process.argv[1], message: String(error) })); })' <entry-id> || true
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The invocation is failure-safe by construction: a rejected import or write resolves to a structured `error` result instead of a crash, and the trailing `|| true` absorbs any remaining non-zero exit (missing `node`, unresolvable package). Record an `error` or non-zero outcome in the cycle summary and continue — the bump must never abort the lifecycle.
|
|
272
|
+
|
|
273
|
+
`confirmLearningEntry` advances ONLY `last_confirmed` — rule text, why, provenance, `first_learned`, and confidence are untouched — and is idempotent within a claim: a repeat same-date bump returns `unchanged`, so an entry that applied repeatedly during one claim is bumped once, not once per application.
|
|
274
|
+
3. **Never block on it.** A failed bump, an unwritable file, or a `not-found` result (the entry was pruned) is recorded under the cycle summary and the claim proceeds — shipping the ticket always outranks confirming a learning about it.
|
|
275
|
+
|
|
260
276
|
#### 3d. Transition to $DONE (only after the PR is merged)
|
|
261
277
|
|
|
262
278
|
A `done` env status (`On Dev`, `On Stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Setting `On Stg` on an open PR makes a ticket *claim* a deploy that never happened. Transition only after confirming the PR merged.
|
|
@@ -250,6 +250,22 @@ If the canonical fix is merged but not yet present on the production branch, app
|
|
|
250
250
|
|
|
251
251
|
This path is distinct from `BLOCKED`: ambiguity, open blockers, and duplicate-of-open findings remain held for human action and must not be auto-closed.
|
|
252
252
|
|
|
253
|
+
#### 3c.2 Confirm applied learnings (last_confirmed bump)
|
|
254
|
+
|
|
255
|
+
Run this at the end of 3c, after the lifecycle outcome is recorded and before 3d. It keeps the decay pass safe: a genuinely useful learning that keeps applying stays fresh, while dead weight ages out.
|
|
256
|
+
|
|
257
|
+
1. **Identify which learnings demonstrably applied.** Resolve the learnings surface with `resolveProjectLearningsFile` and parse it with `parseLearningsFile` from `@codyswann/lisa/learnings` (never hardcode the path; a missing file skips this step silently). An entry counts as applied ONLY when its rule was explicitly cited or observably followed in this claim's plan, diff, or review responses — the plan quotes the rule or its id, or the diff does specifically what the rule mandates where the default behavior would have differed. **Presence in context is NOT application**: the ledger is loaded eagerly into every session, so counting "it was loaded" would confirm every entry on every claim and defeat decay entirely. A run that produced no plan or diff has nothing to confirm.
|
|
258
|
+
2. **Bump each applied entry exactly once** via the surgical writer:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
node -e 'import("@codyswann/lisa/learnings").then(async m => { const r = await m.confirmLearningEntry(process.cwd(), process.argv[1], new Date().toISOString().slice(0, 10)); console.log(JSON.stringify(r)); }).catch(error => { console.log(JSON.stringify({ status: "error", id: process.argv[1], message: String(error) })); })' <entry-id> || true
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The invocation is failure-safe by construction: a rejected import or write resolves to a structured `error` result instead of a crash, and the trailing `|| true` absorbs any remaining non-zero exit (missing `node`, unresolvable package). Record an `error` or non-zero outcome in the cycle summary and continue — the bump must never abort the lifecycle.
|
|
265
|
+
|
|
266
|
+
`confirmLearningEntry` advances ONLY `last_confirmed` — rule text, why, provenance, `first_learned`, and confidence are untouched — and is idempotent within a claim: a repeat same-date bump returns `unchanged`, so an entry that applied repeatedly during one claim is bumped once, not once per application.
|
|
267
|
+
3. **Never block on it.** A failed bump, an unwritable file, or a `not-found` result (the entry was pruned) is recorded under the cycle summary and the claim proceeds — shipping the Issue always outranks confirming a learning about it.
|
|
268
|
+
|
|
253
269
|
#### 3d. Relabel to $DONE (only after the PR is merged)
|
|
254
270
|
|
|
255
271
|
A `done` env state (`status:on-dev`, `status:on-stg`, or the terminal value) asserts that the code has actually reached that environment. Never set it for a PR that is merely open: auto-merge can be blocked indefinitely (a required rebase / `BEHIND` branch, failing checks, an unaddressed review), and the change may never land. Relabeling an Issue `status:on-stg` on an open PR makes it *claim* a deploy that never happened. Transition only after confirming the PR merged.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lisa-persist-learning
|
|
3
|
-
description: This skill should be used when a candidate learning (from a failure signal, rejection, or debrief) needs to be judged and routed. It computes a stable fingerprint, runs the candidate through the hostile-default learning-judge gate, and performs exactly the verdict's side effects — a dropped-with-reason note on the triggering issue (drop), an upstream
|
|
3
|
+
description: This skill should be used when a candidate learning (from a failure signal, rejection, or debrief) needs to be judged and routed. It computes a stable fingerprint, runs the candidate through the hostile-default learning-judge gate, and performs exactly the verdict's side effects — a dropped-with-reason note on the triggering issue (drop), an automatically filed upstream Lisa ticket with marker dedupe, evidence, and a per-run cap (lisa-upstream), or a confidence-routed pull request that touches only the learnings surface (durable-learning). Idempotent via marker dedupe; headless-safe; never blocks the primary build flow.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Persist Learning
|
|
@@ -62,20 +62,73 @@ The note is one line naming the classification (with its fixed plain-language gl
|
|
|
62
62
|
|----------------|-------|
|
|
63
63
|
| `one-off` | a one-time fluke, not a recurring pattern |
|
|
64
64
|
| `misunderstanding/spec-gap` | traced to an unclear requirement, not a durable lesson |
|
|
65
|
-
| `lisa-upstream` | root cause
|
|
65
|
+
| `lisa-upstream` | root cause suspected in Lisa; routed for upstream attribution |
|
|
66
66
|
|
|
67
|
-
(
|
|
67
|
+
(A `lisa-upstream` classification never produces a drop note — it routes through the `handoff-upstream` flow below, whose step-1 note uses this pre-attribution wording because filing only happens after attribution confirms the Lisa surface.) Dedupe before posting: if any comment on the triggering issue already carries `[lisa-learning-drop] key=<fingerprint>`, do not post again — report the existing note.
|
|
68
68
|
|
|
69
69
|
### `handoff-upstream` (classification `lisa-upstream`)
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
This disposition completes the SLL-5 loop (#1583): on a Lisa-attributed failure the upstream Lisa ticket is filed **automatically**. Filing lives here — not in `lisa-attribute-failure` — because that skill is deliberately read-only (doctor delegates to it inside its own read-only contract), while this skill already owns exactly the verdict's side effects and the marker-dedupe discipline. Never persist a local rule for a Lisa-attributed failure; the host project's only durable trace is the brief linking note in step 6.
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
1. **Post the handoff marker** on the triggering issue (same one-comment marker dedupe; the marker key is unchanged). The visible line must not claim a filing that has not happened yet — attribution and filing come after this step:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
<!-- [lisa-learning-upstream-handoff] key=<fingerprint> -->
|
|
77
|
+
Candidate routed for upstream attribution (root cause suspected in Lisa): <reason>.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
2. **Require a confirmed `lisa` verdict from `lisa-attribute-failure` — always.** Run the `lisa-attribute-failure` skill on the failure event before any filing. The judge's `cited_evidence` seeds the event (implicated files, surface in play, failure class) but never substitutes for the verdict — a path or commit reference alone is not attribution. File **only** when the skill returns a conclusive `lisa` verdict that names the Lisa surface with cited evidence. Any other outcome — `ambiguous`, `project`, or a verdict that cannot name a concrete Lisa surface — files **NOTHING** upstream: the candidate stays local and low-confidence, the run summary says attribution was inconclusive, and the step-1 note is resolved with one corrective follow-up comment on the triggering issue (marker-deduped so re-runs never repeat it; the suffix is distinct from the filing-failure marker in step 8 so one outcome never suppresses the other):
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
<!-- [lisa-learning-upstream-handoff] key=<fingerprint>-inconclusive -->
|
|
84
|
+
Attribution was inconclusive — nothing was filed upstream and nothing was persisted locally.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
3. **Derive the root-cause key from the LISA SURFACE, never the host project or the local issue.** Two projects hitting the same Lisa bug MUST collide on the same key — that collision is the design (update, not duplicate):
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
root-cause-key = <lisa-surface>#<failure-class>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- `<lisa-surface>` — the Lisa-relative path of the surface at fault (e.g. `plugins/src/base/skills/lisa-doctor/SKILL.md`, `typescript/copy-overwrite/.github/workflows/quality.yml`), or the canonical rule/skill/hook name when no single file applies (e.g. `lisa-doctor`, `block-no-verify`).
|
|
94
|
+
- `<failure-class>` — a short lowercase hyphen-slug for the class of failure (e.g. `pagination-truncation`, `stale-artifact-overwrite`).
|
|
95
|
+
- Normalize: lowercase, trim, collapse every whitespace run to a single `-`. The key must contain no host-project name, no local issue number, and no fingerprint — those vary per project and would defeat fleet-wide dedupe.
|
|
96
|
+
|
|
97
|
+
4. **Enforce the per-run cap.** Resolve `hardening.maxUpstreamFilingsPerRun` from `.lisa.config.json` (default `5` — a conservative bound modeled on `lisa-repair-intake`'s `max_candidates` precedent). Count every upstream create **and** update this run performs; once the cap is reached, drop the remaining candidates and **note each dropped candidate visibly** (in the run summary, naming its root-cause key) — never queue a spam burst and never drop silently. A later run picks the dropped candidates up idempotently.
|
|
98
|
+
|
|
99
|
+
5. **Evidence redaction (binding).** The upstream repo is PUBLIC by default (`hardening.upstreamRepo` → `CodySwannGT/lisa`) and this filing runs headless on crons — treat every drafted upstream body and comment as world-readable:
|
|
77
100
|
|
|
78
|
-
|
|
101
|
+
- Quote ONLY Lisa-owned surface text: template/rule/skill/hook excerpts and upstream commit references. The reproduction must be REDACTED — generic placeholders, never the host project's real values.
|
|
102
|
+
- Never paste host environment values, tokens/credentials, connection strings, API keys, PII (names, emails, customer data), or proprietary host code/payloads.
|
|
103
|
+
- The evidence chain names the Lisa surface and the failure class — never project payloads. When host context is essential to understand the failure, LINK the host-project issue instead of quoting it.
|
|
104
|
+
- Before filing or commenting, scan the drafted body for common secret shapes — `key=value` pairs with high-entropy values, token prefixes (`AKIA`, `ghp_`, `xox`), email addresses — and strip on match. When in doubt, leave it out: a thinner upstream ticket is recoverable; a leaked secret is not.
|
|
105
|
+
|
|
106
|
+
6. **Dedupe by marker, then file or update.** The upstream marker is:
|
|
107
|
+
|
|
108
|
+
```markdown
|
|
109
|
+
<!-- [lisa-upstream-attribution] key=<root-cause-key> -->
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Resolve the upstream repo from `.lisa.config.json` `hardening.upstreamRepo` (default `CodySwannGT/lisa`). Search **all issue states** for an existing issue carrying the marker — a closed marker-bearing ticket still owns this root cause, and searching only open issues would mint a duplicate the moment the original closes. Match on the **MARKER, never the title** — with the same eventual-consistency guard as above (`gh issue list -R <upstream> --state all --search '"<marker>" in:body' --json number,state,url`, and when the search index returns nothing, also `gh issue list -R <upstream> --state all --json number,state,body` and grep the bodies for the marker before concluding no ticket exists).
|
|
113
|
+
|
|
114
|
+
- **No existing ticket** → file via `lisa-github-write-issue` targeting the upstream repo, following the `lisa-rework-triage` "Filing upstream" discipline: a three-audience description (what failed for the operator, what the harness did wrong, what to change), the redacted evidence chain (Lisa-owned text only, per step 5: defect → Lisa surface → attribution evidence → redacted reproduction), the affected project named, and the `self-hardening` label. The body carries **exactly one** dedupe marker; **never write a markerless body** — it permanently breaks all future dedupe.
|
|
115
|
+
- **Existing ticket (open or closed)** → this is a repeat encounter: comment the new occurrence on the existing issue with this project's evidence, marker-deduped per occurrence via `<!-- [lisa-upstream-attribution-occurrence] key=<fingerprint> -->` so re-runs never duplicate the occurrence comment. Never open a second issue, and never match on the title — evidence compounds on one ticket. When the match is **CLOSED**, still comment the occurrence there and reference it in the local trace instead of filing a duplicate; do not reopen it yourself — recurrence evidence on a closed ticket signals the shipped fix may not cover this case, and reopening is the upstream maintainer's call.
|
|
116
|
+
|
|
117
|
+
7. **Leave the local trace — a note, never a rule.** Post one follow-up comment on the triggering issue linking the upstream ticket:
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
<!-- [lisa-upstream-filed] key=<fingerprint> -->
|
|
121
|
+
Upstream ticket: <url> (root-cause key `<root-cause-key>`). No local rule persisted — the fix ships fleet-wide through Lisa.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The learnings surface gains **no durable local rule** for a Lisa-attributed failure. Agents avoid the trap via the upstream ticket link until the fix ships.
|
|
125
|
+
|
|
126
|
+
8. **Degrade gracefully.** If filing fails (auth, rate limit, network), report the failure in the run summary and continue shipping the host issue — a later run retries idempotently. Never block the primary build flow. So the step-1 note is not left dangling, post a marker-deduped corrective follow-up on the triggering issue — with its own suffix, distinct from step 2's `-inconclusive`, so an earlier inconclusive note can never suppress a filing-failure note (or vice versa):
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
<!-- [lisa-learning-upstream-handoff] key=<fingerprint>-filing-failed -->
|
|
130
|
+
Upstream filing did not complete — nothing was filed upstream and nothing was persisted locally; a later run retries.
|
|
131
|
+
```
|
|
79
132
|
|
|
80
133
|
### `persist` (classification `durable-learning`)
|
|
81
134
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Attribute an arbitrary failure event to Lisa or the project with cited evidence. Evaluates three ordered signals — Lisa-managed surface ownership, shipped rule/skill/hook behavior, and the upstream Lisa change-history window — and returns lisa | project | ambiguous. Read-only; inconclusive cases stay local as ambiguous."
|
|
3
|
+
argument-hint: "<failure event: defect description, implicated files, rule/skill/hook in play>"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the /lisa-attribute-failure skill to attribute the given failure event to Lisa or the project and return the verdict with its cited evidence. $ARGUMENTS
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Route a candidate learning through the hostile-default learning-judge gate and act on the verdict: leave a dropped-with-reason note on the triggering issue (drop),
|
|
2
|
+
description: "Route a candidate learning through the hostile-default learning-judge gate and act on the verdict: leave a dropped-with-reason note on the triggering issue (drop), file the upstream Lisa ticket automatically with marker dedupe, evidence, and a per-run cap (lisa-upstream), or persist a durable learning via a confidence-routed PR that touches only the learnings surface — auto-merge on for high confidence, auto-merge off plus the learning:needs-triage label for low confidence. Idempotent via marker dedupe."
|
|
3
3
|
argument-hint: "<candidate-json-or-fields>"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -20,6 +20,24 @@ Each persisted entry has seven fields:
|
|
|
20
20
|
- `last_confirmed`
|
|
21
21
|
- `confidence`
|
|
22
22
|
|
|
23
|
+
## Claim-time confirmation (`last_confirmed`)
|
|
24
|
+
|
|
25
|
+
`last_confirmed` is advanced at claim time by the build-intake flows (step
|
|
26
|
+
3c.2 of `lisa-{jira,github,linear}-build-intake`) when an entry's rule
|
|
27
|
+
**demonstrably applied** during a claim — the rule was explicitly cited or
|
|
28
|
+
observably followed in the claim's plan or diff. Presence in the eagerly
|
|
29
|
+
loaded context is NOT application: every entry is present in every session,
|
|
30
|
+
so counting mere presence would confirm everything on every claim and defeat
|
|
31
|
+
decay entirely.
|
|
32
|
+
|
|
33
|
+
The bump goes only through `confirmLearningEntry` from
|
|
34
|
+
`@codyswann/lisa/learnings`: a surgical, lock-protected, atomic write that
|
|
35
|
+
advances only `last_confirmed` (re-validated against the
|
|
36
|
+
`>= first_learned` invariant), returns a structured no-op for a missing
|
|
37
|
+
entry or file instead of throwing, and is idempotent within a claim (a
|
|
38
|
+
same-date repeat returns `unchanged`). A failed bump is reported and never
|
|
39
|
+
blocks the build.
|
|
40
|
+
|
|
23
41
|
Only entries accepted by the executable contract may influence the session. A
|
|
24
42
|
missing file is expected and silent. Malformed Markdown, invalid JSONL, unsafe
|
|
25
43
|
paths, non-canonical content, or over-budget documents produce one readable
|