@codyswann/lisa 3.41.1 → 3.43.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/copy-overwrite/scripts/lisa-environment-prepare.mjs +356 -0
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +203 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +6 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +12 -3
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/expo/create-only/.github/workflows/playwright-e2e.yml +92 -75
- 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-drive-pr-to-merge/SKILL.md +50 -0
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +50 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +50 -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/skills/lisa-drive-pr-to-merge/SKILL.md +50 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +50 -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/skills/lisa-drive-pr-to-merge/SKILL.md +50 -0
|
@@ -5,20 +5,24 @@ name: 🎭 Playwright Web E2E
|
|
|
5
5
|
|
|
6
6
|
# Standalone Playwright suite — the web counterpart to maestro-e2e.yml.
|
|
7
7
|
#
|
|
8
|
-
# WHY THIS EXISTS. Playwright used to ride inside ci.yml as the
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# its own cadence, its own concurrency, one target environment, and a
|
|
14
|
-
# dedicated red/green signal a nightly gate can read.
|
|
8
|
+
# WHY THIS EXISTS. Playwright used to ride inside ci.yml as the `playwright_e2e`
|
|
9
|
+
# job of Lisa's reusable quality.yml. That coupled the heaviest and flakiest
|
|
10
|
+
# suite in the project to the lint/typecheck/unit gate: one workflow, one
|
|
11
|
+
# concurrency group, one cadence, and a red Playwright shard blocking a pull
|
|
12
|
+
# request that only changed a type.
|
|
15
13
|
#
|
|
16
|
-
#
|
|
14
|
+
# It now calls a DEDICATED reusable workflow. The previous shape of this file
|
|
15
|
+
# called quality.yml and passed `skip_jobs` naming the two dozen jobs it did not
|
|
16
|
+
# want — an inversion that went stale silently, because a job added to
|
|
17
|
+
# quality.yml was absent from this hand-maintained list and therefore RAN on a
|
|
18
|
+
# nightly whose whole point is that it runs one suite. That list is gone.
|
|
19
|
+
#
|
|
20
|
+
# ── DECLARING THE GATE ─────────────────────────────────────────────────────
|
|
17
21
|
#
|
|
18
22
|
# This workflow resolves the `e2e-browser` gate at the `continuous:development`
|
|
19
|
-
# moment. Until `.lisa.config.json` declares it,
|
|
20
|
-
# Playwright path
|
|
21
|
-
#
|
|
23
|
+
# moment. Until `.lisa.config.json` declares it, Lisa runs its BUILT-IN
|
|
24
|
+
# Playwright path (sharded `npx playwright test`), which is a reasonable default
|
|
25
|
+
# but is not a decision anybody recorded. To make it one:
|
|
22
26
|
#
|
|
23
27
|
# {
|
|
24
28
|
# "gates": {
|
|
@@ -27,29 +31,21 @@ name: 🎭 Playwright Web E2E
|
|
|
27
31
|
# }
|
|
28
32
|
# }
|
|
29
33
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
34
|
+
# The gate's task is `test:e2e`, so the project needs that script in
|
|
35
|
+
# package.json — Lisa resolves the PROPERTY ("browser journeys pass end to
|
|
36
|
+
# end"), never the tool.
|
|
33
37
|
#
|
|
34
38
|
# TWO THINGS THAT ARE NOT INTERCHANGEABLE:
|
|
35
39
|
#
|
|
36
40
|
# * OMITTING the declaration and declaring it `off` are different. `off` is a
|
|
37
41
|
# recorded decision and drops the required context. Omitting it leaves
|
|
38
42
|
# Lisa's built-in path running. Neither is "no gate".
|
|
39
|
-
# * DECLARING IT WITH NO SUITE is refused, not greened.
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# ── SHARDING ───────────────────────────────────────────────────────────────
|
|
47
|
-
#
|
|
48
|
-
# `playwright_shards` splits Lisa's BUILT-IN invocation across N runners. It
|
|
49
|
-
# does not apply once `e2e-browser` resolves to a task: Lisa cannot append
|
|
50
|
-
# `--shard` to a command whose shape it does not know, and the `--` passthrough
|
|
51
|
-
# differs between npm, yarn and bun. A declared gate runs on one runner. Shard
|
|
52
|
-
# inside the project's own `test:e2e` script if the suite needs it.
|
|
43
|
+
# * DECLARING IT WITH NO SUITE is refused, not greened. The job fails when
|
|
44
|
+
# `e2e-browser` resolves and there is no playwright.config.ts, because a
|
|
45
|
+
# browser gate over an absent suite reports green having run nothing and is
|
|
46
|
+
# indistinguishable on the pull-request page from one that ran. If this
|
|
47
|
+
# project has no Playwright specs, DELETE THIS FILE rather than declaring
|
|
48
|
+
# the gate against it.
|
|
53
49
|
|
|
54
50
|
on:
|
|
55
51
|
schedule:
|
|
@@ -61,14 +57,40 @@ on:
|
|
|
61
57
|
- cron: '0 7 * * *'
|
|
62
58
|
workflow_dispatch:
|
|
63
59
|
|
|
64
|
-
# Deliberately no `pull_request` trigger. This suite is too slow to gate a
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
60
|
+
# Deliberately no `pull_request` trigger. This suite is too slow to gate a pull
|
|
61
|
+
# request, and adding one here would also collide with ci.yml: two workflows
|
|
62
|
+
# must not report the same check name, and the identity is the JOB name, not the
|
|
63
|
+
# workflow's.
|
|
64
|
+
#
|
|
65
|
+
# ── THE COLLISION IS STILL LIVE, AND THIS NOTE IS THE ONLY DEFENCE ─────────
|
|
66
|
+
#
|
|
67
|
+
# quality.yml STILL CONTAINS its own copy of the Playwright jobs. Removing them
|
|
68
|
+
# there is a breaking change for every already-installed caller tracking `@main`,
|
|
69
|
+
# so it happens only once consumers have migrated to the dedicated workflow this
|
|
70
|
+
# file now calls. Until that removal lands, a project that runs quality.yml
|
|
71
|
+
# WITHOUT suppressing the suite runs it in two places and reports the same check
|
|
72
|
+
# name from both.
|
|
73
|
+
#
|
|
74
|
+
# SUPPRESS IT WITH THE GATE, NOT WITH `skip_jobs`. `skip_jobs` is being retired
|
|
75
|
+
# in favour of gate levels, and the gate already controls this suite completely
|
|
76
|
+
# inside quality.yml — `off` reaches the "e2e-browser declared off" path and
|
|
77
|
+
# neither the built-in run nor the declared task executes. So declare it off at
|
|
78
|
+
# the moment ci.yml runs at:
|
|
79
|
+
#
|
|
80
|
+
# {
|
|
81
|
+
# "gates": {
|
|
82
|
+
# "e2e-browser": {
|
|
83
|
+
# "pull-request": "off",
|
|
84
|
+
# "continuous:development": "required"
|
|
85
|
+
# }
|
|
86
|
+
# }
|
|
87
|
+
# }
|
|
88
|
+
#
|
|
89
|
+
# One declaration, both cadences, and each is a recorded decision rather than an
|
|
90
|
+
# inferred one. Declaring `off` also drops the required context, which is the
|
|
91
|
+
# visible way to stop requiring a check — as opposed to a job that silently
|
|
92
|
+
# stops running. Nothing inside this file can enforce it; the only defence is
|
|
93
|
+
# that whoever seeds it knows.
|
|
72
94
|
|
|
73
95
|
permissions:
|
|
74
96
|
contents: read
|
|
@@ -93,49 +115,44 @@ concurrency:
|
|
|
93
115
|
jobs:
|
|
94
116
|
playwright:
|
|
95
117
|
name: 🎭 Playwright Web E2E
|
|
96
|
-
uses: CodySwannGT/lisa/.github/workflows/
|
|
118
|
+
uses: CodySwannGT/lisa/.github/workflows/playwright-e2e.yml@main
|
|
97
119
|
with:
|
|
98
120
|
node_version: '22.21.1'
|
|
99
121
|
package_manager: 'bun'
|
|
100
|
-
# The moment this workflow's cadence corresponds to. It is what makes
|
|
101
|
-
#
|
|
102
|
-
# declared at `pull-request` is invisible at this moment, and vice
|
|
103
|
-
#
|
|
104
|
-
#
|
|
122
|
+
# The moment this workflow's cadence corresponds to. It is what makes the
|
|
123
|
+
# `.lisa.config.json` declaration above readable from here — a gate
|
|
124
|
+
# declared at `pull-request` is invisible at this moment, and vice versa,
|
|
125
|
+
# so a nightly suite and a per-change suite cannot be turned on by the
|
|
126
|
+
# same line of config by accident.
|
|
105
127
|
moment: 'continuous:development'
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
# the
|
|
110
|
-
#
|
|
111
|
-
# two dozen jobs it does NOT want. It is exact-token matched against
|
|
112
|
-
# `,{0},` — comma-delimited with NO SPACES, so `lint, lint_slow`
|
|
113
|
-
# silently skips nothing beyond `lint`.
|
|
114
|
-
#
|
|
115
|
-
# IT GOES STALE SILENTLY, and that is the cost. A job added to
|
|
116
|
-
# quality.yml is absent from this list and therefore RUNS here, on a
|
|
117
|
-
# nightly whose whole point is that it runs one suite. Measured while
|
|
118
|
-
# writing this file: the hand-maintained list in the first project to
|
|
119
|
-
# adopt this shape was already missing five keys that exist today
|
|
120
|
-
# (`bdd_coverage`, `state_classification`, `environment_reset`,
|
|
121
|
-
# `environment_reseed`, `skipped_required_checks`). Re-derive it from
|
|
122
|
-
# quality.yml when adding a suite, do not extend it from memory.
|
|
123
|
-
skip_jobs: 'bdd_coverage,build,dead_code,e2e_coverage,environment_reseed,environment_reset,floor_collisions,format,learnings_budget,license_compliance,lint,lint_slow,maestro_e2e,npm_security_scan,secret_scanning,sg_scan,skipped_required_checks,snyk,sonarcloud,state_classification,test:e2e,test:integration,test:mutation,test:unit,test_node_suites,threshold_ratchet,typecheck,work_item_traceability,zap_baseline'
|
|
124
|
-
# Cross-run mutex on whatever this suite shares with the OTHER suites
|
|
125
|
-
# that touch the same backend. Deliberately DISTINCT from this
|
|
126
|
-
# workflow's own top-level `concurrency` group above — a shared group
|
|
127
|
-
# between a parent run and the child run it is waiting on deadlocks.
|
|
128
|
-
# Join maestro-e2e.yml to the same group if the two suites share test
|
|
129
|
-
# accounts or fixtures.
|
|
128
|
+
# Cross-run mutex on whatever this suite shares with the OTHER suites that
|
|
129
|
+
# touch the same backend. Deliberately DISTINCT from this workflow's own
|
|
130
|
+
# top-level `concurrency` group above — a shared group between a parent
|
|
131
|
+
# run and the child run it is waiting on deadlocks. Join maestro-e2e.yml
|
|
132
|
+
# to the same group if the two suites share test accounts or fixtures.
|
|
130
133
|
concurrency_group: 'e2e-shared-development'
|
|
131
|
-
#
|
|
132
|
-
#
|
|
134
|
+
# Return the environment to a known state BEFORE the suite, rather than
|
|
135
|
+
# cleaning up after it. Cleanup-after is best-effort: it does not run when
|
|
136
|
+
# a runner dies, is cancelled, or is evicted, so the next night starts
|
|
137
|
+
# against whatever the last failure left behind.
|
|
138
|
+
#
|
|
139
|
+
# The named verbs must exist as `environment:reset` / `environment:reseed`
|
|
140
|
+
# scripts. A verb named here that the project does not declare FAILS the
|
|
141
|
+
# run rather than skipping — a suite against an environment nobody
|
|
142
|
+
# prepared reports green while proving nothing. Clear this input to opt
|
|
143
|
+
# out; that is a visible decision, which a silent skip is not.
|
|
144
|
+
prepare_environment: 'development'
|
|
145
|
+
prepare_verbs: 'reset,reseed'
|
|
146
|
+
# Applies only while `e2e-browser` is undeclared: Lisa cannot append
|
|
147
|
+
# `--shard` to a command whose shape it does not know, and the `--`
|
|
148
|
+
# passthrough differs between npm, yarn and bun. A declared gate runs on
|
|
149
|
+
# one runner; shard inside the project's own `test:e2e` script instead.
|
|
133
150
|
playwright_shards: 2
|
|
134
|
-
# Leave false unless the cache key has been checked against this
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
151
|
+
# Leave false unless the cache key has been checked against this project's
|
|
152
|
+
# layout. Lisa's key is a fingerprint of build inputs, and a key that
|
|
153
|
+
# misses the project's source directories freezes: `expo export` then
|
|
154
|
+
# serves stale transforms and every source change silently tests old code.
|
|
155
|
+
# A green suite over the previous commit is the worst failure this
|
|
139
156
|
# workflow has.
|
|
140
157
|
cache_build: false
|
|
141
158
|
# Runs before the web export, in the job that runs the suite. Bake the
|
|
@@ -145,7 +162,7 @@ jobs:
|
|
|
145
162
|
#
|
|
146
163
|
# Use `printf '\n%s\n'` rather than `echo >>`: the committed .env.<mode>
|
|
147
164
|
# files do not end in a trailing newline, so a bare append concatenates
|
|
148
|
-
# onto the last variable's value — corrupting it AND silently dropping
|
|
149
|
-
#
|
|
165
|
+
# onto the last variable's value — corrupting it AND silently dropping the
|
|
166
|
+
# line being added.
|
|
150
167
|
playwright_setup_command: |
|
|
151
168
|
cp .env.development .env.local
|
package/package.json
CHANGED
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"ws": ">=8.21.0"
|
|
133
133
|
},
|
|
134
134
|
"name": "@codyswann/lisa",
|
|
135
|
-
"version": "3.
|
|
135
|
+
"version": "3.43.0",
|
|
136
136
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
137
137
|
"main": "dist/index.js",
|
|
138
138
|
"exports": {
|
|
@@ -470,6 +470,56 @@ matching Phase 4b's safe default. The full procedure is `lisa-linear-sync`
|
|
|
470
470
|
Phase 4b; when the caller's flow already runs a `pr-merged` sync for this
|
|
471
471
|
merge, confirming that sync ran satisfies this step.
|
|
472
472
|
|
|
473
|
+
### d. Complete the work item
|
|
474
|
+
|
|
475
|
+
Run this once the PR reports `MERGED` and the ancestry check has passed:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
node scripts/lisa-work-item.mjs complete --ref <work-item>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
resolving the script the usual three ways (installed package, host `scripts/`,
|
|
482
|
+
this repo's own tree).
|
|
483
|
+
|
|
484
|
+
**This step exists because the previous arrangement did not work, measured.**
|
|
485
|
+
The instruction to move a work item to its terminal role lived in
|
|
486
|
+
`lisa-git-submit-pr`, in a section reached *after* that skill delegates the
|
|
487
|
+
entire merge loop to this one. So the skill that observes the merge was never
|
|
488
|
+
told to close anything, and the skill that was told had already handed off. The
|
|
489
|
+
result: **27 of 27** open items carrying the claimed role in this repository had
|
|
490
|
+
a merged pull request — the claimed lane reported 27 things in flight when the
|
|
491
|
+
real number was one.
|
|
492
|
+
|
|
493
|
+
Three properties make the command safe to run unconditionally:
|
|
494
|
+
|
|
495
|
+
1. **The terminal role is RESOLVED, never assumed.** `lifecycleContract` reads
|
|
496
|
+
`github.labels.build.done` (or the Jira/Linear equivalent), which is
|
|
497
|
+
environment-aware — a repository whose target is `dev` has a different
|
|
498
|
+
terminal role than one merging to production, and a hardcoded label would
|
|
499
|
+
apply the wrong one while looking correct in the repository it was written
|
|
500
|
+
in.
|
|
501
|
+
2. **It refuses without evidence.** Completion requires a merged pull request in
|
|
502
|
+
the same repository. A command that closes whatever it is pointed at is a way
|
|
503
|
+
to make unfinished work disappear, and the closure is indistinguishable from
|
|
504
|
+
a real one afterwards. Cross-repository references do not count: a downstream
|
|
505
|
+
consumer's PR mentioning an upstream issue is not evidence the upstream issue
|
|
506
|
+
shipped.
|
|
507
|
+
3. **It is idempotent**, so re-running after a retry converges rather than
|
|
508
|
+
accumulating.
|
|
509
|
+
|
|
510
|
+
It also removes the claimed role rather than only adding the terminal one.
|
|
511
|
+
Leaving both produces exactly the drift this step exists to end — an item that
|
|
512
|
+
is closed *and* still reports as in progress.
|
|
513
|
+
|
|
514
|
+
If the command refuses, do not close by hand. A refusal means the evidence is
|
|
515
|
+
not there, and a lifecycle step performed by hand is one nothing can verify
|
|
516
|
+
happened.
|
|
517
|
+
|
|
518
|
+
**The backstop, for the ones that still slip:** `lisa-work-item.mjs sweep`
|
|
519
|
+
reports every claimed item that already has a merged pull request, and
|
|
520
|
+
`--apply` completes them. Reporting is the default deliberately — a sweep that
|
|
521
|
+
closes things as a side effect of being run is not one anyone runs twice.
|
|
522
|
+
|
|
473
523
|
## 4. Terminal states
|
|
474
524
|
|
|
475
525
|
Loop until one of:
|
|
@@ -470,6 +470,56 @@ matching Phase 4b's safe default. The full procedure is `lisa-linear-sync`
|
|
|
470
470
|
Phase 4b; when the caller's flow already runs a `pr-merged` sync for this
|
|
471
471
|
merge, confirming that sync ran satisfies this step.
|
|
472
472
|
|
|
473
|
+
### d. Complete the work item
|
|
474
|
+
|
|
475
|
+
Run this once the PR reports `MERGED` and the ancestry check has passed:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
node scripts/lisa-work-item.mjs complete --ref <work-item>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
resolving the script the usual three ways (installed package, host `scripts/`,
|
|
482
|
+
this repo's own tree).
|
|
483
|
+
|
|
484
|
+
**This step exists because the previous arrangement did not work, measured.**
|
|
485
|
+
The instruction to move a work item to its terminal role lived in
|
|
486
|
+
`lisa-git-submit-pr`, in a section reached *after* that skill delegates the
|
|
487
|
+
entire merge loop to this one. So the skill that observes the merge was never
|
|
488
|
+
told to close anything, and the skill that was told had already handed off. The
|
|
489
|
+
result: **27 of 27** open items carrying the claimed role in this repository had
|
|
490
|
+
a merged pull request — the claimed lane reported 27 things in flight when the
|
|
491
|
+
real number was one.
|
|
492
|
+
|
|
493
|
+
Three properties make the command safe to run unconditionally:
|
|
494
|
+
|
|
495
|
+
1. **The terminal role is RESOLVED, never assumed.** `lifecycleContract` reads
|
|
496
|
+
`github.labels.build.done` (or the Jira/Linear equivalent), which is
|
|
497
|
+
environment-aware — a repository whose target is `dev` has a different
|
|
498
|
+
terminal role than one merging to production, and a hardcoded label would
|
|
499
|
+
apply the wrong one while looking correct in the repository it was written
|
|
500
|
+
in.
|
|
501
|
+
2. **It refuses without evidence.** Completion requires a merged pull request in
|
|
502
|
+
the same repository. A command that closes whatever it is pointed at is a way
|
|
503
|
+
to make unfinished work disappear, and the closure is indistinguishable from
|
|
504
|
+
a real one afterwards. Cross-repository references do not count: a downstream
|
|
505
|
+
consumer's PR mentioning an upstream issue is not evidence the upstream issue
|
|
506
|
+
shipped.
|
|
507
|
+
3. **It is idempotent**, so re-running after a retry converges rather than
|
|
508
|
+
accumulating.
|
|
509
|
+
|
|
510
|
+
It also removes the claimed role rather than only adding the terminal one.
|
|
511
|
+
Leaving both produces exactly the drift this step exists to end — an item that
|
|
512
|
+
is closed *and* still reports as in progress.
|
|
513
|
+
|
|
514
|
+
If the command refuses, do not close by hand. A refusal means the evidence is
|
|
515
|
+
not there, and a lifecycle step performed by hand is one nothing can verify
|
|
516
|
+
happened.
|
|
517
|
+
|
|
518
|
+
**The backstop, for the ones that still slip:** `lisa-work-item.mjs sweep`
|
|
519
|
+
reports every claimed item that already has a merged pull request, and
|
|
520
|
+
`--apply` completes them. Reporting is the default deliberately — a sweep that
|
|
521
|
+
closes things as a side effect of being run is not one anyone runs twice.
|
|
522
|
+
|
|
473
523
|
## 4. Terminal states
|
|
474
524
|
|
|
475
525
|
Loop until one of:
|
|
@@ -470,6 +470,56 @@ matching Phase 4b's safe default. The full procedure is `lisa-linear-sync`
|
|
|
470
470
|
Phase 4b; when the caller's flow already runs a `pr-merged` sync for this
|
|
471
471
|
merge, confirming that sync ran satisfies this step.
|
|
472
472
|
|
|
473
|
+
### d. Complete the work item
|
|
474
|
+
|
|
475
|
+
Run this once the PR reports `MERGED` and the ancestry check has passed:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
node scripts/lisa-work-item.mjs complete --ref <work-item>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
resolving the script the usual three ways (installed package, host `scripts/`,
|
|
482
|
+
this repo's own tree).
|
|
483
|
+
|
|
484
|
+
**This step exists because the previous arrangement did not work, measured.**
|
|
485
|
+
The instruction to move a work item to its terminal role lived in
|
|
486
|
+
`lisa-git-submit-pr`, in a section reached *after* that skill delegates the
|
|
487
|
+
entire merge loop to this one. So the skill that observes the merge was never
|
|
488
|
+
told to close anything, and the skill that was told had already handed off. The
|
|
489
|
+
result: **27 of 27** open items carrying the claimed role in this repository had
|
|
490
|
+
a merged pull request — the claimed lane reported 27 things in flight when the
|
|
491
|
+
real number was one.
|
|
492
|
+
|
|
493
|
+
Three properties make the command safe to run unconditionally:
|
|
494
|
+
|
|
495
|
+
1. **The terminal role is RESOLVED, never assumed.** `lifecycleContract` reads
|
|
496
|
+
`github.labels.build.done` (or the Jira/Linear equivalent), which is
|
|
497
|
+
environment-aware — a repository whose target is `dev` has a different
|
|
498
|
+
terminal role than one merging to production, and a hardcoded label would
|
|
499
|
+
apply the wrong one while looking correct in the repository it was written
|
|
500
|
+
in.
|
|
501
|
+
2. **It refuses without evidence.** Completion requires a merged pull request in
|
|
502
|
+
the same repository. A command that closes whatever it is pointed at is a way
|
|
503
|
+
to make unfinished work disappear, and the closure is indistinguishable from
|
|
504
|
+
a real one afterwards. Cross-repository references do not count: a downstream
|
|
505
|
+
consumer's PR mentioning an upstream issue is not evidence the upstream issue
|
|
506
|
+
shipped.
|
|
507
|
+
3. **It is idempotent**, so re-running after a retry converges rather than
|
|
508
|
+
accumulating.
|
|
509
|
+
|
|
510
|
+
It also removes the claimed role rather than only adding the terminal one.
|
|
511
|
+
Leaving both produces exactly the drift this step exists to end — an item that
|
|
512
|
+
is closed *and* still reports as in progress.
|
|
513
|
+
|
|
514
|
+
If the command refuses, do not close by hand. A refusal means the evidence is
|
|
515
|
+
not there, and a lifecycle step performed by hand is one nothing can verify
|
|
516
|
+
happened.
|
|
517
|
+
|
|
518
|
+
**The backstop, for the ones that still slip:** `lisa-work-item.mjs sweep`
|
|
519
|
+
reports every claimed item that already has a merged pull request, and
|
|
520
|
+
`--apply` completes them. Reporting is the default deliberately — a sweep that
|
|
521
|
+
closes things as a side effect of being run is not one anyone runs twice.
|
|
522
|
+
|
|
473
523
|
## 4. Terminal states
|
|
474
524
|
|
|
475
525
|
Loop until one of:
|
|
@@ -470,6 +470,56 @@ matching Phase 4b's safe default. The full procedure is `lisa-linear-sync`
|
|
|
470
470
|
Phase 4b; when the caller's flow already runs a `pr-merged` sync for this
|
|
471
471
|
merge, confirming that sync ran satisfies this step.
|
|
472
472
|
|
|
473
|
+
### d. Complete the work item
|
|
474
|
+
|
|
475
|
+
Run this once the PR reports `MERGED` and the ancestry check has passed:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
node scripts/lisa-work-item.mjs complete --ref <work-item>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
resolving the script the usual three ways (installed package, host `scripts/`,
|
|
482
|
+
this repo's own tree).
|
|
483
|
+
|
|
484
|
+
**This step exists because the previous arrangement did not work, measured.**
|
|
485
|
+
The instruction to move a work item to its terminal role lived in
|
|
486
|
+
`lisa-git-submit-pr`, in a section reached *after* that skill delegates the
|
|
487
|
+
entire merge loop to this one. So the skill that observes the merge was never
|
|
488
|
+
told to close anything, and the skill that was told had already handed off. The
|
|
489
|
+
result: **27 of 27** open items carrying the claimed role in this repository had
|
|
490
|
+
a merged pull request — the claimed lane reported 27 things in flight when the
|
|
491
|
+
real number was one.
|
|
492
|
+
|
|
493
|
+
Three properties make the command safe to run unconditionally:
|
|
494
|
+
|
|
495
|
+
1. **The terminal role is RESOLVED, never assumed.** `lifecycleContract` reads
|
|
496
|
+
`github.labels.build.done` (or the Jira/Linear equivalent), which is
|
|
497
|
+
environment-aware — a repository whose target is `dev` has a different
|
|
498
|
+
terminal role than one merging to production, and a hardcoded label would
|
|
499
|
+
apply the wrong one while looking correct in the repository it was written
|
|
500
|
+
in.
|
|
501
|
+
2. **It refuses without evidence.** Completion requires a merged pull request in
|
|
502
|
+
the same repository. A command that closes whatever it is pointed at is a way
|
|
503
|
+
to make unfinished work disappear, and the closure is indistinguishable from
|
|
504
|
+
a real one afterwards. Cross-repository references do not count: a downstream
|
|
505
|
+
consumer's PR mentioning an upstream issue is not evidence the upstream issue
|
|
506
|
+
shipped.
|
|
507
|
+
3. **It is idempotent**, so re-running after a retry converges rather than
|
|
508
|
+
accumulating.
|
|
509
|
+
|
|
510
|
+
It also removes the claimed role rather than only adding the terminal one.
|
|
511
|
+
Leaving both produces exactly the drift this step exists to end — an item that
|
|
512
|
+
is closed *and* still reports as in progress.
|
|
513
|
+
|
|
514
|
+
If the command refuses, do not close by hand. A refusal means the evidence is
|
|
515
|
+
not there, and a lifecycle step performed by hand is one nothing can verify
|
|
516
|
+
happened.
|
|
517
|
+
|
|
518
|
+
**The backstop, for the ones that still slip:** `lisa-work-item.mjs sweep`
|
|
519
|
+
reports every claimed item that already has a merged pull request, and
|
|
520
|
+
`--apply` completes them. Reporting is the default deliberately — a sweep that
|
|
521
|
+
closes things as a side effect of being run is not one anyone runs twice.
|
|
522
|
+
|
|
473
523
|
## 4. Terminal states
|
|
474
524
|
|
|
475
525
|
Loop until one of:
|
|
@@ -470,6 +470,56 @@ matching Phase 4b's safe default. The full procedure is `lisa-linear-sync`
|
|
|
470
470
|
Phase 4b; when the caller's flow already runs a `pr-merged` sync for this
|
|
471
471
|
merge, confirming that sync ran satisfies this step.
|
|
472
472
|
|
|
473
|
+
### d. Complete the work item
|
|
474
|
+
|
|
475
|
+
Run this once the PR reports `MERGED` and the ancestry check has passed:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
node scripts/lisa-work-item.mjs complete --ref <work-item>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
resolving the script the usual three ways (installed package, host `scripts/`,
|
|
482
|
+
this repo's own tree).
|
|
483
|
+
|
|
484
|
+
**This step exists because the previous arrangement did not work, measured.**
|
|
485
|
+
The instruction to move a work item to its terminal role lived in
|
|
486
|
+
`lisa-git-submit-pr`, in a section reached *after* that skill delegates the
|
|
487
|
+
entire merge loop to this one. So the skill that observes the merge was never
|
|
488
|
+
told to close anything, and the skill that was told had already handed off. The
|
|
489
|
+
result: **27 of 27** open items carrying the claimed role in this repository had
|
|
490
|
+
a merged pull request — the claimed lane reported 27 things in flight when the
|
|
491
|
+
real number was one.
|
|
492
|
+
|
|
493
|
+
Three properties make the command safe to run unconditionally:
|
|
494
|
+
|
|
495
|
+
1. **The terminal role is RESOLVED, never assumed.** `lifecycleContract` reads
|
|
496
|
+
`github.labels.build.done` (or the Jira/Linear equivalent), which is
|
|
497
|
+
environment-aware — a repository whose target is `dev` has a different
|
|
498
|
+
terminal role than one merging to production, and a hardcoded label would
|
|
499
|
+
apply the wrong one while looking correct in the repository it was written
|
|
500
|
+
in.
|
|
501
|
+
2. **It refuses without evidence.** Completion requires a merged pull request in
|
|
502
|
+
the same repository. A command that closes whatever it is pointed at is a way
|
|
503
|
+
to make unfinished work disappear, and the closure is indistinguishable from
|
|
504
|
+
a real one afterwards. Cross-repository references do not count: a downstream
|
|
505
|
+
consumer's PR mentioning an upstream issue is not evidence the upstream issue
|
|
506
|
+
shipped.
|
|
507
|
+
3. **It is idempotent**, so re-running after a retry converges rather than
|
|
508
|
+
accumulating.
|
|
509
|
+
|
|
510
|
+
It also removes the claimed role rather than only adding the terminal one.
|
|
511
|
+
Leaving both produces exactly the drift this step exists to end — an item that
|
|
512
|
+
is closed *and* still reports as in progress.
|
|
513
|
+
|
|
514
|
+
If the command refuses, do not close by hand. A refusal means the evidence is
|
|
515
|
+
not there, and a lifecycle step performed by hand is one nothing can verify
|
|
516
|
+
happened.
|
|
517
|
+
|
|
518
|
+
**The backstop, for the ones that still slip:** `lisa-work-item.mjs sweep`
|
|
519
|
+
reports every claimed item that already has a merged pull request, and
|
|
520
|
+
`--apply` completes them. Reporting is the default deliberately — a sweep that
|
|
521
|
+
closes things as a side effect of being run is not one anyone runs twice.
|
|
522
|
+
|
|
473
523
|
## 4. Terminal states
|
|
474
524
|
|
|
475
525
|
Loop until one of:
|