@codyswann/lisa 3.33.5 → 3.33.7
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/check-state-classification.mjs +18 -4
- package/all/copy-overwrite/scripts/lisa-gates.mjs +47 -46
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +3 -2
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +284 -2
- package/dist/configs/eslint/base.d.ts +21 -0
- package/dist/configs/eslint/base.d.ts.map +1 -1
- package/dist/configs/eslint/base.js +78 -2
- package/dist/configs/eslint/base.js.map +1 -1
- package/dist/configs/eslint/cdk.d.ts.map +1 -1
- package/dist/configs/eslint/cdk.js +5 -1
- package/dist/configs/eslint/cdk.js.map +1 -1
- package/dist/configs/eslint/expo.d.ts.map +1 -1
- package/dist/configs/eslint/expo.js +5 -1
- package/dist/configs/eslint/expo.js.map +1 -1
- package/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
- package/dist/configs/eslint/harper-fabric.js +6 -1
- package/dist/configs/eslint/harper-fabric.js.map +1 -1
- package/dist/configs/eslint/nestjs.d.ts.map +1 -1
- package/dist/configs/eslint/nestjs.js +5 -1
- package/dist/configs/eslint/nestjs.js.map +1 -1
- package/dist/configs/eslint/phaser.d.ts.map +1 -1
- package/dist/configs/eslint/phaser.js +6 -1
- package/dist/configs/eslint/phaser.js.map +1 -1
- package/dist/configs/eslint/typescript.d.ts +2 -2
- package/dist/configs/eslint/typescript.d.ts.map +1 -1
- package/dist/configs/eslint/typescript.js +6 -2
- package/dist/configs/eslint/typescript.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +12 -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 +36 -35
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +11 -4
- package/expo/copy-overwrite/scripts/bdd/discover.mjs +12 -6
- package/expo/copy-overwrite/scripts/bdd/waivers.mjs +7 -4
- package/expo/copy-overwrite/scripts/bdd-matrix.mjs +1 -0
- package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +26 -17
- package/expo/copy-overwrite/scripts/check-e2e-coverage.mjs +12 -8
- 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-git-submit-pr/SKILL.md +11 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +7 -2
- package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +11 -4
- package/plugins/lisa/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/lisa/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +7 -2
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +11 -4
- package/plugins/lisa-agy/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +7 -2
- 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-git-submit-pr/SKILL.md +11 -4
- package/plugins/lisa-copilot/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +7 -2
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +11 -4
- package/plugins/lisa-cursor/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +7 -2
- 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-git-submit-pr/SKILL.md +11 -4
- package/plugins/src/base/skills/lisa-github-sync/SKILL.md +7 -2
- package/plugins/src/base/skills/lisa-implement/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-jira-sync/SKILL.md +7 -2
- package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +7 -2
- package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +7 -2
- package/scripts/check-conflict-markers.mjs +1 -1
- package/scripts/check-required-check-promotions.mjs +8 -4
- package/scripts/detect-stale-workflow-inputs.mjs +1 -3
- package/scripts/fix-namespace-test-assertions.mjs +1 -1
- package/scripts/generate-agy-plugin-artifacts.mjs +12 -7
- package/scripts/generate-codex-plugin-artifacts.mjs +14 -9
- package/scripts/generate-copilot-plugin-artifacts.mjs +1 -1
- package/scripts/generate-cursor-plugin-artifacts.mjs +2 -2
- package/scripts/generate-upstream-evidence-manifest.mjs +1 -1
- package/scripts/lisa-assert-eas-profile.mjs +3 -3
- package/scripts/plugin-parity-drift.mjs +29 -13
- package/scripts/plugin-routing-validate.mjs +8 -2
- package/scripts/update-node-version.ts +7 -3
- package/scripts/verify-health-agentic-built.mjs +27 -20
- package/scripts/verify-health-consumer-built.mjs +7 -3
- package/scripts/verify-health-deterministic-built.mjs +24 -19
- package/typescript/copy-overwrite/eslint.ignore.config.json +0 -2
- package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +9 -4
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +1 -3
|
@@ -38,6 +38,9 @@ import { parseFeatureSource, scenarioIdsIn } from "./parse.mjs";
|
|
|
38
38
|
|
|
39
39
|
const defect = (code, message) => ({ code, message });
|
|
40
40
|
|
|
41
|
+
/** Defect / evidence code, named once. */
|
|
42
|
+
const SCENARIO_DELETED = "scenario-deleted";
|
|
43
|
+
|
|
41
44
|
/** The maintainer-applied PR label that authorizes giving coverage back. */
|
|
42
45
|
export const BASELINE_LABEL = "bdd-floor-baseline";
|
|
43
46
|
|
|
@@ -247,10 +250,14 @@ export function obligationKeys(scenarios, contract) {
|
|
|
247
250
|
|
|
248
251
|
/**
|
|
249
252
|
* Every `SCENARIO:platform` a waiver removes from the denominator.
|
|
253
|
+
*
|
|
254
|
+
* Exported because `bdd-matrix.mjs` calls it too. It was calling it WITHOUT an
|
|
255
|
+
* import — a live ReferenceError on every matrix render, invisible because this
|
|
256
|
+
* whole tree sat outside the ESLint config until #2658 put it back in.
|
|
250
257
|
* @param {object|null} contract - A coverage map.
|
|
251
258
|
* @returns {Set<string>} Waived keys.
|
|
252
259
|
*/
|
|
253
|
-
function waivedKeys(contract) {
|
|
260
|
+
export function waivedKeys(contract) {
|
|
254
261
|
return new Set(
|
|
255
262
|
(contract?.platformWaivers ?? []).flatMap(waiver =>
|
|
256
263
|
(waiver.platforms ?? []).map(platform => `${waiver.scenario}:${platform}`)
|
|
@@ -420,19 +427,19 @@ function deletionDefects(id, record, labels) {
|
|
|
420
427
|
if (!record) {
|
|
421
428
|
return [
|
|
422
429
|
defect(
|
|
423
|
-
|
|
430
|
+
SCENARIO_DELETED,
|
|
424
431
|
`${id} was deleted from the contract. Retiring a behavior is @superseded, not deletion — deleting it shrinks the denominator instead of the gap. A genuine removal needs a retirements record and the "${BASELINE_LABEL}" label.`
|
|
425
432
|
),
|
|
426
433
|
];
|
|
427
434
|
}
|
|
428
435
|
const missing = RETIREMENT_FIELDS.filter(field => !record[field]);
|
|
429
436
|
const defects = missing.map(field =>
|
|
430
|
-
defect(
|
|
437
|
+
defect(SCENARIO_DELETED, `${id}: retirements record has no ${field}`)
|
|
431
438
|
);
|
|
432
439
|
if (!labels.includes(BASELINE_LABEL)) {
|
|
433
440
|
defects.push(
|
|
434
441
|
defect(
|
|
435
|
-
|
|
442
|
+
SCENARIO_DELETED,
|
|
436
443
|
`${id}: a retirement needs the maintainer-applied "${BASELINE_LABEL}" label`
|
|
437
444
|
)
|
|
438
445
|
);
|
|
@@ -69,6 +69,12 @@ export function isUnderPrefix(relative, prefix) {
|
|
|
69
69
|
*/
|
|
70
70
|
const defect = (code, message, subject) => ({ code, message, subject });
|
|
71
71
|
|
|
72
|
+
/** Defect / evidence code, named once. */
|
|
73
|
+
const CALL_TITLE = "call-title";
|
|
74
|
+
|
|
75
|
+
/** Defect / evidence code, named once. */
|
|
76
|
+
const EXCLUSION_STALE = "exclusion-stale";
|
|
77
|
+
|
|
72
78
|
/**
|
|
73
79
|
* The evidence grammars a project may choose from, as SOURCE CONSTANTS.
|
|
74
80
|
*
|
|
@@ -78,7 +84,7 @@ const defect = (code, message, subject) => ({ code, message, subject });
|
|
|
78
84
|
* (`test("...")`, `it.skip('...')`); `line-field` reads a leading document
|
|
79
85
|
* field (`name: ...`), which is how flow-style runners title a file.
|
|
80
86
|
*/
|
|
81
|
-
export const EVIDENCE_KINDS = Object.freeze([
|
|
87
|
+
export const EVIDENCE_KINDS = Object.freeze([CALL_TITLE, "line-field"]);
|
|
82
88
|
|
|
83
89
|
/** A JavaScript identifier, the only shape a declared function name may take. */
|
|
84
90
|
const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
@@ -176,7 +182,7 @@ function evidenceProblems(evidence) {
|
|
|
176
182
|
`evidence.kind ${JSON.stringify(evidence.kind)} is not one of ${EVIDENCE_KINDS.join(", ")}`,
|
|
177
183
|
];
|
|
178
184
|
}
|
|
179
|
-
if (evidence.kind ===
|
|
185
|
+
if (evidence.kind === CALL_TITLE) {
|
|
180
186
|
return isListOf(
|
|
181
187
|
evidence.functions,
|
|
182
188
|
entry => typeof entry === "string" && IDENTIFIER.test(entry)
|
|
@@ -316,7 +322,7 @@ function discoverRunner({ root, runner, config, contract }) {
|
|
|
316
322
|
* @returns {{evidence: string|null, dynamic: boolean}[]} Discovered entries.
|
|
317
323
|
*/
|
|
318
324
|
function extract(source, evidence) {
|
|
319
|
-
return evidence.kind ===
|
|
325
|
+
return evidence.kind === CALL_TITLE
|
|
320
326
|
? callTitles(source, evidence.functions)
|
|
321
327
|
: lineField(source, evidence.field);
|
|
322
328
|
}
|
|
@@ -485,7 +491,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
|
|
|
485
491
|
if (!resolved.path) {
|
|
486
492
|
return [
|
|
487
493
|
defect(
|
|
488
|
-
|
|
494
|
+
EXCLUSION_STALE,
|
|
489
495
|
`${at}: ${exclusion.file} — ${resolved.error}; retire the exclusion or restore the file`,
|
|
490
496
|
subject
|
|
491
497
|
),
|
|
@@ -494,7 +500,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
|
|
|
494
500
|
if (!discovery.roots.some(entry => isUnderPrefix(exclusion.file, entry))) {
|
|
495
501
|
return [
|
|
496
502
|
defect(
|
|
497
|
-
|
|
503
|
+
EXCLUSION_STALE,
|
|
498
504
|
`${at}: ${exclusion.file} is covered by no configured discovery root (${discovery.roots.map(entry => entry || ".").join(", ") || "none declared"}), so the exclusion suppresses nothing`,
|
|
499
505
|
subject
|
|
500
506
|
),
|
|
@@ -504,7 +510,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
|
|
|
504
510
|
? []
|
|
505
511
|
: [
|
|
506
512
|
defect(
|
|
507
|
-
|
|
513
|
+
EXCLUSION_STALE,
|
|
508
514
|
`${at}: no discovered test in ${exclusion.file} matches ${JSON.stringify(exclusion.evidence)}`,
|
|
509
515
|
subject
|
|
510
516
|
),
|
|
@@ -24,6 +24,9 @@ const REQUIRED_FIELDS = [
|
|
|
24
24
|
"expiresAt",
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
+
/** Defect / evidence code, named once. */
|
|
28
|
+
const WAIVER_METADATA = "waiver-metadata";
|
|
29
|
+
|
|
27
30
|
/** ISO calendar date, the only accepted date shape. */
|
|
28
31
|
export const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
29
32
|
|
|
@@ -48,7 +51,7 @@ export function validateWaivers({ scenarios, contract, today }) {
|
|
|
48
51
|
? []
|
|
49
52
|
: [
|
|
50
53
|
defect(
|
|
51
|
-
|
|
54
|
+
WAIVER_METADATA,
|
|
52
55
|
`the evaluation date ${JSON.stringify(today ?? null)} is not an ISO date (YYYY-MM-DD), so no waiver expiry could be evaluated. Set BDD_TODAY to a calendar date or leave it unset.`
|
|
53
56
|
),
|
|
54
57
|
];
|
|
@@ -118,13 +121,13 @@ function blockingError(waiver, scenario, at) {
|
|
|
118
121
|
*/
|
|
119
122
|
function metadataDefects(waiver, at, today) {
|
|
120
123
|
const defects = REQUIRED_FIELDS.filter(field => !waiver[field]).map(field =>
|
|
121
|
-
defect(
|
|
124
|
+
defect(WAIVER_METADATA, `${at}: has no ${field}`)
|
|
122
125
|
);
|
|
123
126
|
for (const field of ["recordedAt", "expiresAt"]) {
|
|
124
127
|
if (waiver[field] && !ISO_DATE.test(waiver[field])) {
|
|
125
128
|
defects.push(
|
|
126
129
|
defect(
|
|
127
|
-
|
|
130
|
+
WAIVER_METADATA,
|
|
128
131
|
`${at}: ${field} must be an ISO date (YYYY-MM-DD)`
|
|
129
132
|
)
|
|
130
133
|
);
|
|
@@ -136,7 +139,7 @@ function metadataDefects(waiver, at, today) {
|
|
|
136
139
|
) {
|
|
137
140
|
defects.push(
|
|
138
141
|
defect(
|
|
139
|
-
|
|
142
|
+
WAIVER_METADATA,
|
|
140
143
|
`${at}: ticket ${waiver.ticket} is not a valid tracker reference`
|
|
141
144
|
)
|
|
142
145
|
);
|
|
@@ -23,6 +23,7 @@ import * as fs from "node:fs";
|
|
|
23
23
|
import * as path from "node:path";
|
|
24
24
|
import { fileURLToPath } from "node:url";
|
|
25
25
|
|
|
26
|
+
import { waivedKeys } from "./bdd/baseline.mjs";
|
|
26
27
|
import { byCodeUnit, declaredPlatforms, trackerUrl } from "./bdd/contract.mjs";
|
|
27
28
|
import { loadScenarios } from "./bdd/parse.mjs";
|
|
28
29
|
import { indexResults } from "./bdd/report.mjs";
|
|
@@ -90,6 +90,18 @@ const PACKAGE_ROOT = path.resolve(
|
|
|
90
90
|
const MAP_REL = "bdd/coverage-map.json";
|
|
91
91
|
const defect = (code, message) => ({ code, message });
|
|
92
92
|
|
|
93
|
+
/** Defect / mode code, named once. */
|
|
94
|
+
const NOT_ADOPTED = "not-adopted";
|
|
95
|
+
|
|
96
|
+
/** Defect / mode code, named once. */
|
|
97
|
+
const BOOTSTRAP_METADATA = "bootstrap-metadata";
|
|
98
|
+
|
|
99
|
+
/** Defect / mode code, named once. */
|
|
100
|
+
const EXECUTION_RESULTS = "execution-results";
|
|
101
|
+
|
|
102
|
+
/** Defect / mode code, named once. */
|
|
103
|
+
const EMPTY_CONTRACT = "empty-contract";
|
|
104
|
+
|
|
93
105
|
/**
|
|
94
106
|
* Resolve the adoption state from the environment.
|
|
95
107
|
* @param {Record<string, string|undefined>} env - Process environment.
|
|
@@ -97,10 +109,10 @@ const defect = (code, message) => ({ code, message });
|
|
|
97
109
|
*/
|
|
98
110
|
export function resolveMode(env) {
|
|
99
111
|
const raw = (env.BDD_MODE ?? "").trim();
|
|
100
|
-
if (raw === "") return { mode:
|
|
112
|
+
if (raw === "") return { mode: NOT_ADOPTED, error: null };
|
|
101
113
|
if (!ADOPTION_STATES.includes(raw)) {
|
|
102
114
|
return {
|
|
103
|
-
mode:
|
|
115
|
+
mode: NOT_ADOPTED,
|
|
104
116
|
error: `BDD_MODE="${raw}" is not one of ${ADOPTION_STATES.join(", ")}`,
|
|
105
117
|
};
|
|
106
118
|
}
|
|
@@ -188,7 +200,7 @@ function bootstrapDefects(adoption, today) {
|
|
|
188
200
|
// would make the time-box unreachable and bootstrap permanent.
|
|
189
201
|
defects.push(
|
|
190
202
|
defect(
|
|
191
|
-
|
|
203
|
+
BOOTSTRAP_METADATA,
|
|
192
204
|
`the evaluation date ${JSON.stringify(today ?? null)} is not an ISO date (YYYY-MM-DD), so the bootstrap expiry could not be evaluated`
|
|
193
205
|
)
|
|
194
206
|
);
|
|
@@ -196,7 +208,7 @@ function bootstrapDefects(adoption, today) {
|
|
|
196
208
|
if (!adoption.owner) {
|
|
197
209
|
defects.push(
|
|
198
210
|
defect(
|
|
199
|
-
|
|
211
|
+
BOOTSTRAP_METADATA,
|
|
200
212
|
"bootstrap requires adoption.owner (a named person, not a team)"
|
|
201
213
|
)
|
|
202
214
|
);
|
|
@@ -204,14 +216,14 @@ function bootstrapDefects(adoption, today) {
|
|
|
204
216
|
if (!adoption.expiresAt) {
|
|
205
217
|
defects.push(
|
|
206
218
|
defect(
|
|
207
|
-
|
|
219
|
+
BOOTSTRAP_METADATA,
|
|
208
220
|
"bootstrap requires adoption.expiresAt (an ISO date); a bootstrap with no time-box never ends"
|
|
209
221
|
)
|
|
210
222
|
);
|
|
211
223
|
} else if (!ISO_DATE.test(adoption.expiresAt)) {
|
|
212
224
|
defects.push(
|
|
213
225
|
defect(
|
|
214
|
-
|
|
226
|
+
BOOTSTRAP_METADATA,
|
|
215
227
|
"adoption.expiresAt must be an ISO date (YYYY-MM-DD)"
|
|
216
228
|
)
|
|
217
229
|
);
|
|
@@ -239,7 +251,7 @@ export function loadExecutionResults(root, files) {
|
|
|
239
251
|
const resolved = path.resolve(root, file);
|
|
240
252
|
if (!fs.existsSync(resolved)) {
|
|
241
253
|
defects.push(
|
|
242
|
-
defect(
|
|
254
|
+
defect(EXECUTION_RESULTS, `execution results not found: ${file}`)
|
|
243
255
|
);
|
|
244
256
|
continue;
|
|
245
257
|
}
|
|
@@ -248,17 +260,14 @@ export function loadExecutionResults(root, files) {
|
|
|
248
260
|
for (const run of Array.isArray(parsed) ? parsed : [parsed]) {
|
|
249
261
|
if (!run.runner) {
|
|
250
262
|
defects.push(
|
|
251
|
-
defect(
|
|
252
|
-
"execution-results",
|
|
253
|
-
`${file}: each run must name its runner`
|
|
254
|
-
)
|
|
263
|
+
defect(EXECUTION_RESULTS, `${file}: each run must name its runner`)
|
|
255
264
|
);
|
|
256
265
|
continue;
|
|
257
266
|
}
|
|
258
267
|
runs.push(run);
|
|
259
268
|
}
|
|
260
269
|
} catch (error) {
|
|
261
|
-
defects.push(defect(
|
|
270
|
+
defects.push(defect(EXECUTION_RESULTS, `${file}: ${error.message}`));
|
|
262
271
|
}
|
|
263
272
|
}
|
|
264
273
|
return { runs, defects };
|
|
@@ -372,7 +381,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
|
|
|
372
381
|
if (scenarios.length === 0) {
|
|
373
382
|
defects.push(
|
|
374
383
|
defect(
|
|
375
|
-
|
|
384
|
+
EMPTY_CONTRACT,
|
|
376
385
|
"enforced mode: bdd/features declares zero scenarios"
|
|
377
386
|
)
|
|
378
387
|
);
|
|
@@ -380,7 +389,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
|
|
|
380
389
|
if ((contract.mappings ?? []).length === 0) {
|
|
381
390
|
defects.push(
|
|
382
391
|
defect(
|
|
383
|
-
|
|
392
|
+
EMPTY_CONTRACT,
|
|
384
393
|
"enforced mode: bdd/coverage-map.json declares zero test mappings"
|
|
385
394
|
)
|
|
386
395
|
);
|
|
@@ -388,7 +397,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
|
|
|
388
397
|
if (Object.keys(contract.runnerPlatforms ?? {}).length === 0) {
|
|
389
398
|
defects.push(
|
|
390
399
|
defect(
|
|
391
|
-
|
|
400
|
+
EMPTY_CONTRACT,
|
|
392
401
|
"enforced mode: bdd/coverage-map.json declares no runnerPlatforms"
|
|
393
402
|
)
|
|
394
403
|
);
|
|
@@ -494,7 +503,7 @@ export function run(root, options) {
|
|
|
494
503
|
*/
|
|
495
504
|
function configFatals(loaded, mode) {
|
|
496
505
|
if (loaded.error) return defect("config-malformed", loaded.error);
|
|
497
|
-
if (loaded.present || mode ===
|
|
506
|
+
if (loaded.present || mode === NOT_ADOPTED) return null;
|
|
498
507
|
return defect(
|
|
499
508
|
"config-absent",
|
|
500
509
|
`${mode} mode requires ${MAP_REL}, which does not exist. In ${mode} mode absence is a failure, never a skip.`
|
|
@@ -562,7 +571,7 @@ function result({ mode, defects, report, contract }) {
|
|
|
562
571
|
function statusFor({ mode, defects, fatal, report }) {
|
|
563
572
|
if (defects.some(item => INVALID_CODES.includes(item.code))) return "invalid";
|
|
564
573
|
if (fatal) return "failed";
|
|
565
|
-
if (mode ===
|
|
574
|
+
if (mode === NOT_ADOPTED && !report) return NOT_ADOPTED;
|
|
566
575
|
return "completed";
|
|
567
576
|
}
|
|
568
577
|
|
|
@@ -596,21 +596,24 @@ function main() {
|
|
|
596
596
|
]) {
|
|
597
597
|
if (collected.skipped.length > 0) {
|
|
598
598
|
console.log(
|
|
599
|
-
`[e2e-coverage] ${runner}: ${collected.skipped.length} file(s) excluded from the run and NOT counted as coverage:\n
|
|
600
|
-
|
|
599
|
+
`[e2e-coverage] ${runner}: ${collected.skipped.length} file(s) excluded from the run and NOT counted as coverage:\n${collected.skipped
|
|
600
|
+
.map(file => ` - ${file}`)
|
|
601
|
+
.join("\n")}`
|
|
601
602
|
);
|
|
602
603
|
}
|
|
603
604
|
}
|
|
604
605
|
if (exempt.length > 0) {
|
|
605
606
|
console.log(
|
|
606
|
-
`[e2e-coverage] ${exempt.length} route(s) deliberately exempt (removed from the denominator):\n
|
|
607
|
-
|
|
607
|
+
`[e2e-coverage] ${exempt.length} route(s) deliberately exempt (removed from the denominator):\n${exempt
|
|
608
|
+
.map(route => ` - ${route}`)
|
|
609
|
+
.join("\n")}`
|
|
608
610
|
);
|
|
609
611
|
}
|
|
610
612
|
if (unknown.length > 0) {
|
|
611
613
|
console.error(
|
|
612
|
-
`[e2e-coverage] FAIL: ${unknown.length} exemption(s) name a route that does not exist. A waiver that outlived its screen permanently excuses whatever replaces it:\n
|
|
613
|
-
|
|
614
|
+
`[e2e-coverage] FAIL: ${unknown.length} exemption(s) name a route that does not exist. A waiver that outlived its screen permanently excuses whatever replaces it:\n${unknown
|
|
615
|
+
.map(route => ` - ${route}`)
|
|
616
|
+
.join("\n")}`
|
|
614
617
|
);
|
|
615
618
|
process.exit(1);
|
|
616
619
|
return;
|
|
@@ -641,8 +644,9 @@ function main() {
|
|
|
641
644
|
} else {
|
|
642
645
|
console.error(`[e2e-coverage] ${runner}: FAIL — ${summary}`);
|
|
643
646
|
console.error(
|
|
644
|
-
`[e2e-coverage] ${runner}: screens with no e2e test yet:\n
|
|
645
|
-
|
|
647
|
+
`[e2e-coverage] ${runner}: screens with no e2e test yet:\n${verdict.missing
|
|
648
|
+
.map(route => ` - ${route}`)
|
|
649
|
+
.join("\n")}`
|
|
646
650
|
);
|
|
647
651
|
}
|
|
648
652
|
}
|
package/package.json
CHANGED
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"ws": ">=8.21.0"
|
|
132
132
|
},
|
|
133
133
|
"name": "@codyswann/lisa",
|
|
134
|
-
"version": "3.33.
|
|
134
|
+
"version": "3.33.7",
|
|
135
135
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
136
136
|
"main": "dist/index.js",
|
|
137
137
|
"exports": {
|
|
@@ -66,10 +66,17 @@ When updating an existing PR, preserve any existing linkage line unless the new
|
|
|
66
66
|
After creating or updating the PR, always make the reverse link durable on the source work item when `work_item_ref` is available:
|
|
67
67
|
|
|
68
68
|
1. Resolve the live PR URL with `gh pr view <pr-number> --json url --jq .url`.
|
|
69
|
-
2.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
2. Run the backlink command. It is the executable form of this requirement — it writes the managed `[lisa-pr-link]` comment on the work item, or updates the one already there, for every tracker Lisa supports:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
node scripts/lisa-work-item.mjs backlink --ref <work_item_ref> --pr-url <url>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
It is idempotent, so run it on every push rather than deciding whether it is needed. It refuses loudly for a tracker it cannot write, and never silently no-ops. Do not hand-post the comment, and do not describe the posting procedure anywhere: the same file that writes it is the file that checks it, which is what keeps producer and consumer from drifting.
|
|
76
|
+
3. Invoke `lisa-tracker-sync` with the original work item ref, milestone `pr-ready`, `pr_url=<url>`, and `tracker_provider=<provider>` when known. That is the progress-note and status side; it is not what satisfies the traceability check.
|
|
77
|
+
4. When the PR later merges, invoke `lisa-tracker-sync` again with milestone `pr-merged`, the same `pr_url`, and the merge SHA when available.
|
|
78
|
+
|
|
79
|
+
**Why step 2 exists — do not "simplify" it away as redundant with the `Refs` line.** Under the non-closing rule above, GitHub never creates a native development link at all: that surface *is* the closing-reference mechanism, so no non-closing form can populate it. A PR carrying a perfectly correct `Refs` line still fails the required Work-Item Traceability check without the comment. The managed comment is the ticket-side half of the link, not a fallback for when native linkage happens to be absent.
|
|
73
80
|
|
|
74
81
|
Do not report PR submission as fully synced while the PR body references the ticket but the ticket has neither a verified native PR link nor the managed backlink comment.
|
|
75
82
|
|
|
@@ -57,8 +57,13 @@ Optional arguments include `pr_url=<url>` for the live pull request and `merge_s
|
|
|
57
57
|
When `$ARGUMENTS` includes `pr_url=<url>` for `PR ready` or `PR merged`, ensure the GitHub Issue has a durable ticket -> PR link:
|
|
58
58
|
|
|
59
59
|
1. Make sure the PR body contains `Refs #<n>` (or the fully qualified cross-repo form) — never a closing keyword, per the GitHub rule in `lisa-git-submit-pr`. Read the issue side with `gh api graphql` against `issue.timelineItems`, or `gh issue view <number> --json closedByPullRequestsReferences`. **Not** `gh issue view --json timelineItems`: `timelineItems` is not a supported field for that command, so the check silently returns nothing useful rather than failing loudly.
|
|
60
|
-
2.
|
|
61
|
-
|
|
60
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional**, not contingent on step 1 failing: under the non-closing rule GitHub never creates a native development link (that surface is the closing-reference mechanism), so this comment is the only ticket-side backlink there will be — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
62
67
|
|
|
63
68
|
Native GitHub linkage cannot be verified under the non-closing rule because it is never created in the first place, so the managed comment is not a contingency here — it is the mechanism. The issue must show the PR from at least one ticket-side surface, and this is the only one available.
|
|
64
69
|
|
|
@@ -341,7 +341,7 @@ Before shutting down the team, execute the Verify flow:
|
|
|
341
341
|
5. Commit ALL outstanding changes in logical batches on the branch (minus sensitive data/information) — not just changes made by the agent team. This includes pre-existing uncommitted changes that were on the branch before the plan started. Do NOT filter commits to only "task-related" files. If it shows up in git status, it gets committed (unless it contains secrets).
|
|
342
342
|
6. Push the changes - if any pre-push hook blocks you, create a task for the agent team to fix the error/problem whether it was pre-existing or not
|
|
343
343
|
7. Open a pull request with auto-merge on via `lisa-git-submit-pr`, targeting the **base branch resolved from the ticket's environment** (`target_branch=<base>`, per the branch step above), and including the mandatory work-item ref so the PR can be linked natively to the source issue.
|
|
344
|
-
7a. Confirm two-way linkage before treating PR submission as complete: the PR body/title/branch must reference the work item, and the work item must have either a verified native PR link or
|
|
344
|
+
7a. Confirm two-way linkage before treating PR submission as complete: the PR body/title/branch must reference the work item, and the work item must have either a verified native PR link or the single managed `[lisa-pr-link]` comment. Establish that comment with `node scripts/lisa-work-item.mjs backlink --ref <work_item_ref> --pr-url <url>` rather than posting it by hand — it is idempotent, and it is the same file that enforces the check, so producer and consumer cannot drift.
|
|
345
345
|
8. PR Watch Loop: Drive the PR to merge via the `drive-pr-to-merge` skill — the single source of truth for clearing every blocker (auto-merge with direct-merge fallback, `BEHIND` re-sync, conflict resolution, failing-check fixes, human + bot review-comment handling with thread resolution, stale `CHANGES_REQUESTED` dismissal, and post-merge ancestry verification). `git-submit-pr` already invokes it; if you reach this step with a PR already open, invoke `drive-pr-to-merge` directly with the PR number. For a large review backlog you may fan the code-fix work out to the agent team, but `drive-pr-to-merge` owns the loop and the terminal conditions — do not re-implement them.
|
|
346
346
|
9. Merge the PR, then refresh the ticket-side backlink with `lisa-tracker-sync <work_item_ref> pr-merged pr_url=<url> merge_sha=<sha> tracker_provider=<provider>`.
|
|
347
347
|
10. Monitor the deploy action that triggers automatically from the successful merge
|
|
@@ -55,8 +55,13 @@ Before adding a comment, check for an existing milestone comment to avoid duplic
|
|
|
55
55
|
When `$ARGUMENTS` includes `pr_url=<url>` for `PR ready` or `PR merged`, ensure the JIRA ticket has a durable ticket -> PR link:
|
|
56
56
|
|
|
57
57
|
1. Prefer the JIRA development-link surface when the site's GitHub/JIRA integration or remote-link API is available through `lisa-atlassian-access`; verify by re-reading the ticket's remote links / development metadata.
|
|
58
|
-
2.
|
|
59
|
-
|
|
58
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional** — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
60
65
|
|
|
61
66
|
The PR body/branch issue key is the PR -> ticket side. This step is the required ticket -> PR side.
|
|
62
67
|
|
|
@@ -72,8 +72,13 @@ Call `lisa-linear-access operation: save-comment({issueId: <id>, body: <comment>
|
|
|
72
72
|
When `$ARGUMENTS` includes `pr_url=<url>` for `pr-ready` or `pr-merged`, ensure the Linear Issue has a durable ticket -> PR link:
|
|
73
73
|
|
|
74
74
|
1. Prefer Linear's native GitHub attachment / pull request link when the integration has attached the PR through the branch name, PR title, or PR body issue identifier. Verify by re-reading the Issue and its attachments / relations where the Linear access layer exposes them.
|
|
75
|
-
2.
|
|
76
|
-
|
|
75
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional** — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
77
82
|
|
|
78
83
|
The PR branch/title/body identifier is the PR -> Linear side. This phase is the required Linear -> PR side.
|
|
79
84
|
|
|
@@ -52,8 +52,13 @@ When `$ARGUMENTS` includes `pr_url=<url>` with milestone `pr-ready` or `pr-merge
|
|
|
52
52
|
|
|
53
53
|
1. Prefer the provider's native development-link primitive when Lisa can write and verify it for that provider.
|
|
54
54
|
2. Verify the native link using the provider read surface when available.
|
|
55
|
-
3.
|
|
56
|
-
|
|
55
|
+
3. Whether or not the native link exists or cannot be verified, establish the managed backlink comment with the one command that owns it:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
4. That command is idempotent by construction — it updates the existing `[lisa-pr-link]` comment rather than appending duplicates — and it refuses loudly for a tracker it cannot write. Do not restate its procedure in a vendor skill; the file that writes the comment is the file that checks it, and that is what stops the two from drifting.
|
|
57
62
|
|
|
58
63
|
This is the reverse half of `lisa-git-submit-pr`'s PR body linkage. A PR that mentions a ticket is not considered fully synced until the ticket also has either a verified native PR link or the managed fallback comment.
|
|
59
64
|
|
|
@@ -66,10 +66,17 @@ When updating an existing PR, preserve any existing linkage line unless the new
|
|
|
66
66
|
After creating or updating the PR, always make the reverse link durable on the source work item when `work_item_ref` is available:
|
|
67
67
|
|
|
68
68
|
1. Resolve the live PR URL with `gh pr view <pr-number> --json url --jq .url`.
|
|
69
|
-
2.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
2. Run the backlink command. It is the executable form of this requirement — it writes the managed `[lisa-pr-link]` comment on the work item, or updates the one already there, for every tracker Lisa supports:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
node scripts/lisa-work-item.mjs backlink --ref <work_item_ref> --pr-url <url>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
It is idempotent, so run it on every push rather than deciding whether it is needed. It refuses loudly for a tracker it cannot write, and never silently no-ops. Do not hand-post the comment, and do not describe the posting procedure anywhere: the same file that writes it is the file that checks it, which is what keeps producer and consumer from drifting.
|
|
76
|
+
3. Invoke `lisa-tracker-sync` with the original work item ref, milestone `pr-ready`, `pr_url=<url>`, and `tracker_provider=<provider>` when known. That is the progress-note and status side; it is not what satisfies the traceability check.
|
|
77
|
+
4. When the PR later merges, invoke `lisa-tracker-sync` again with milestone `pr-merged`, the same `pr_url`, and the merge SHA when available.
|
|
78
|
+
|
|
79
|
+
**Why step 2 exists — do not "simplify" it away as redundant with the `Refs` line.** Under the non-closing rule above, GitHub never creates a native development link at all: that surface *is* the closing-reference mechanism, so no non-closing form can populate it. A PR carrying a perfectly correct `Refs` line still fails the required Work-Item Traceability check without the comment. The managed comment is the ticket-side half of the link, not a fallback for when native linkage happens to be absent.
|
|
73
80
|
|
|
74
81
|
Do not report PR submission as fully synced while the PR body references the ticket but the ticket has neither a verified native PR link nor the managed backlink comment.
|
|
75
82
|
|
|
@@ -57,8 +57,13 @@ Optional arguments include `pr_url=<url>` for the live pull request and `merge_s
|
|
|
57
57
|
When `$ARGUMENTS` includes `pr_url=<url>` for `PR ready` or `PR merged`, ensure the GitHub Issue has a durable ticket -> PR link:
|
|
58
58
|
|
|
59
59
|
1. Make sure the PR body contains `Refs #<n>` (or the fully qualified cross-repo form) — never a closing keyword, per the GitHub rule in `lisa-git-submit-pr`. Read the issue side with `gh api graphql` against `issue.timelineItems`, or `gh issue view <number> --json closedByPullRequestsReferences`. **Not** `gh issue view --json timelineItems`: `timelineItems` is not a supported field for that command, so the check silently returns nothing useful rather than failing loudly.
|
|
60
|
-
2.
|
|
61
|
-
|
|
60
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional**, not contingent on step 1 failing: under the non-closing rule GitHub never creates a native development link (that surface is the closing-reference mechanism), so this comment is the only ticket-side backlink there will be — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
62
67
|
|
|
63
68
|
Native GitHub linkage cannot be verified under the non-closing rule because it is never created in the first place, so the managed comment is not a contingency here — it is the mechanism. The issue must show the PR from at least one ticket-side surface, and this is the only one available.
|
|
64
69
|
|
|
@@ -341,7 +341,7 @@ Before shutting down the team, execute the Verify flow:
|
|
|
341
341
|
5. Commit ALL outstanding changes in logical batches on the branch (minus sensitive data/information) — not just changes made by the agent team. This includes pre-existing uncommitted changes that were on the branch before the plan started. Do NOT filter commits to only "task-related" files. If it shows up in git status, it gets committed (unless it contains secrets).
|
|
342
342
|
6. Push the changes - if any pre-push hook blocks you, create a task for the agent team to fix the error/problem whether it was pre-existing or not
|
|
343
343
|
7. Open a pull request with auto-merge on via `lisa-git-submit-pr`, targeting the **base branch resolved from the ticket's environment** (`target_branch=<base>`, per the branch step above), and including the mandatory work-item ref so the PR can be linked natively to the source issue.
|
|
344
|
-
7a. Confirm two-way linkage before treating PR submission as complete: the PR body/title/branch must reference the work item, and the work item must have either a verified native PR link or
|
|
344
|
+
7a. Confirm two-way linkage before treating PR submission as complete: the PR body/title/branch must reference the work item, and the work item must have either a verified native PR link or the single managed `[lisa-pr-link]` comment. Establish that comment with `node scripts/lisa-work-item.mjs backlink --ref <work_item_ref> --pr-url <url>` rather than posting it by hand — it is idempotent, and it is the same file that enforces the check, so producer and consumer cannot drift.
|
|
345
345
|
8. PR Watch Loop: Drive the PR to merge via the `drive-pr-to-merge` skill — the single source of truth for clearing every blocker (auto-merge with direct-merge fallback, `BEHIND` re-sync, conflict resolution, failing-check fixes, human + bot review-comment handling with thread resolution, stale `CHANGES_REQUESTED` dismissal, and post-merge ancestry verification). `git-submit-pr` already invokes it; if you reach this step with a PR already open, invoke `drive-pr-to-merge` directly with the PR number. For a large review backlog you may fan the code-fix work out to the agent team, but `drive-pr-to-merge` owns the loop and the terminal conditions — do not re-implement them.
|
|
346
346
|
9. Merge the PR, then refresh the ticket-side backlink with `lisa-tracker-sync <work_item_ref> pr-merged pr_url=<url> merge_sha=<sha> tracker_provider=<provider>`.
|
|
347
347
|
10. Monitor the deploy action that triggers automatically from the successful merge
|
|
@@ -55,8 +55,13 @@ Before adding a comment, check for an existing milestone comment to avoid duplic
|
|
|
55
55
|
When `$ARGUMENTS` includes `pr_url=<url>` for `PR ready` or `PR merged`, ensure the JIRA ticket has a durable ticket -> PR link:
|
|
56
56
|
|
|
57
57
|
1. Prefer the JIRA development-link surface when the site's GitHub/JIRA integration or remote-link API is available through `lisa-atlassian-access`; verify by re-reading the ticket's remote links / development metadata.
|
|
58
|
-
2.
|
|
59
|
-
|
|
58
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional** — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
60
65
|
|
|
61
66
|
The PR body/branch issue key is the PR -> ticket side. This step is the required ticket -> PR side.
|
|
62
67
|
|
|
@@ -72,8 +72,13 @@ Call `lisa-linear-access operation: save-comment({issueId: <id>, body: <comment>
|
|
|
72
72
|
When `$ARGUMENTS` includes `pr_url=<url>` for `pr-ready` or `pr-merged`, ensure the Linear Issue has a durable ticket -> PR link:
|
|
73
73
|
|
|
74
74
|
1. Prefer Linear's native GitHub attachment / pull request link when the integration has attached the PR through the branch name, PR title, or PR body issue identifier. Verify by re-reading the Issue and its attachments / relations where the Linear access layer exposes them.
|
|
75
|
-
2.
|
|
76
|
-
|
|
75
|
+
2. Establish the managed backlink comment by running the command that owns it — never by hand, and never by describing the procedure here:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
It creates the `[lisa-pr-link]` comment or updates the one already present, instead of appending duplicates, so it is safe to run on every milestone. This is **unconditional** — run it whether or not native linkage exists or cannot be verified, because the required Work-Item Traceability check reads this comment and nothing else guarantees one. The comment carries the marker and the PR URL only; the milestone (`pr-ready` / `pr-merged`) and merge SHA belong in the milestone progress note, so that a rerun at a new milestone still converges on one backlink comment.
|
|
77
82
|
|
|
78
83
|
The PR branch/title/body identifier is the PR -> Linear side. This phase is the required Linear -> PR side.
|
|
79
84
|
|
|
@@ -52,8 +52,13 @@ When `$ARGUMENTS` includes `pr_url=<url>` with milestone `pr-ready` or `pr-merge
|
|
|
52
52
|
|
|
53
53
|
1. Prefer the provider's native development-link primitive when Lisa can write and verify it for that provider.
|
|
54
54
|
2. Verify the native link using the provider read surface when available.
|
|
55
|
-
3.
|
|
56
|
-
|
|
55
|
+
3. Whether or not the native link exists or cannot be verified, establish the managed backlink comment with the one command that owns it:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
4. That command is idempotent by construction — it updates the existing `[lisa-pr-link]` comment rather than appending duplicates — and it refuses loudly for a tracker it cannot write. Do not restate its procedure in a vendor skill; the file that writes the comment is the file that checks it, and that is what stops the two from drifting.
|
|
57
62
|
|
|
58
63
|
This is the reverse half of `lisa-git-submit-pr`'s PR body linkage. A PR that mentions a ticket is not considered fully synced until the ticket also has either a verified native PR link or the managed fallback comment.
|
|
59
64
|
|