@alecsibilia/luca 14.0.0-alpha.20 → 14.0.0-alpha.21

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @alecsibilia/luca
2
2
 
3
+ ## 14.0.0-alpha.21
4
+
5
+ No changes in this release.
6
+
3
7
  ## 14.0.0-alpha.20
4
8
 
5
9
  No changes in this release.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luca/board",
3
- "version": "14.0.0-alpha.20",
3
+ "version": "14.0.0-alpha.21",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -1,2 +1,2 @@
1
1
  /** The Luca version of this board, stamped when the package was packed. */
2
- export const LUCA_VERSION: string = "14.0.0-alpha.20"
2
+ export const LUCA_VERSION: string = "14.0.0-alpha.21"
@@ -70,6 +70,9 @@ export const COMMON = `## Rules for every agent
70
70
  - Work only inside your worktree (your current folder).
71
71
  - Anything you change that your role may not change is undone after your turn, and your try counts as failed.
72
72
  - If something is unclear, make your best call and list it under "assumptions". Don't stop to ask.
73
+ - An assumption is a call you made that the owner might disagree with, such as a behaviour, a wording, or a limit the ticket didn't settle.
74
+ - These are not assumptions: following your instructions (such as relying on the engine's gates or reviewing only the new changes), the names you picked for internal code, and how you wrote a test.
75
+ - On a later turn, such as a fix round, list only new assumptions, not ones you already listed in an earlier turn.
73
76
  - "run_notes": at most 3 short facts about this repo that would help later agents in this run. Can be empty.
74
77
  - Finish by giving your structured result. A turn without one counts as failed.`
75
78
 
@@ -77,7 +80,7 @@ export const COMMON = `## Rules for every agent
77
80
  export const SANDBOX = `## Your sandbox
78
81
  - The engine runs the gates (tests, types, lint) outside your sandbox and gives you their results.
79
82
  - The sandbox blocks the network and local ports, writes outside your worktree, git internals, \`node_modules\`, lockfiles, test setup files, test files for roles that may not edit them, and secret files.
80
- - A command that fails only inside your sandbox isn't yours to fix or work around. Rely on the engine's gate results, and say so.`
83
+ - A command that fails only inside your sandbox isn't yours to fix or work around. Rely on the engine's gate results.`
81
84
 
82
85
  /**
83
86
  * The writers' list of the repo's rule files (#646), named, not pasted in,
@@ -7,6 +7,10 @@ export const PIN_TEXT = 'pin the exact text'
7
7
  export const UNTESTABLE_TEXT =
8
8
  'no agent can check this; move it out of the acceptance criteria'
9
9
 
10
+ /** The fix intake asks for when a criterion describes what stays as it is. */
11
+ export const UNCHANGED_TEXT =
12
+ "describes behaviour that doesn't change, so no test can fail first; move it out of the acceptance criteria (for example into the ticket's notes)"
13
+
10
14
  /**
11
15
  * Text that leaves an agent to guess, caught anywhere in a criterion, inside
12
16
  * quotes and code spans too (#541).
@@ -28,6 +32,16 @@ const UNTESTABLE_ASKS: RegExp[] = [
28
32
  /\bADR[\s#-]*\d+/g,
29
33
  ]
30
34
 
35
+ /**
36
+ * Phrases for behaviour that doesn't change, caught outside code spans only
37
+ * (#653): no test can fail first on them.
38
+ */
39
+ const UNCHANGED_PHRASES: RegExp[] = [
40
+ /\bunchanged\b/gi,
41
+ /\bstays? the same\b/gi,
42
+ /\bas (?:today|before)\b/gi,
43
+ ]
44
+
31
45
  /** Inline code spans: a run of backticks up to the same run. */
32
46
  const CODE_SPAN = /(`+)[\s\S]*?\1/g
33
47
 
@@ -59,8 +73,10 @@ const asCode = (text: string): string => {
59
73
 
60
74
  /**
61
75
  * Intake's problems with one ticket's acceptance criteria: a placeholder
62
- * anywhere in a criterion, or an untestable ask (a screenshot, a changeset,
63
- * an ADR number) outside its code spans. Each problem names the ticket,
76
+ * anywhere in a criterion, an untestable ask (a screenshot, a changeset,
77
+ * an ADR number) outside its code spans, or, outside its code spans, words
78
+ * for behaviour that doesn't change ("unchanged", "stays the same", "as
79
+ * today", "as before"), once per criterion. Each problem names the ticket,
64
80
  * quotes the criterion, and says what to do. Pure. Empty when all are clean.
65
81
  *
66
82
  * @example
@@ -78,10 +94,10 @@ export const criteriaProblems = ({
78
94
  const named = `Acceptance criterion ${id} of #${ticket}`
79
95
  const quoted = `It reads: ${asCode(text)}`
80
96
  const placeholders = found({ text, patterns: PLACEHOLDERS })
81
- const asks = found({
82
- text: text.replace(CODE_SPAN, ' '),
83
- patterns: UNTESTABLE_ASKS,
84
- })
97
+ const prose = text.replace(CODE_SPAN, ' ')
98
+ const asks = found({ text: prose, patterns: UNTESTABLE_ASKS })
99
+ const unchanged =
100
+ found({ text: prose, patterns: UNCHANGED_PHRASES }).length > 0
85
101
  return [
86
102
  ...(placeholders.length === 0
87
103
  ? []
@@ -93,5 +109,6 @@ export const criteriaProblems = ({
93
109
  : [
94
110
  `${named} asks for ${asks.map(asCode).join(', ')}: ${UNTESTABLE_TEXT}. ${quoted}`,
95
111
  ]),
112
+ ...(unchanged ? [`${named} ${UNCHANGED_TEXT}. ${quoted}`] : []),
96
113
  ]
97
114
  })
@@ -279,8 +279,9 @@ export const configProblems = ({
279
279
  * too, but still checked, so a later run can build it. The run builds the
280
280
  * rest. A ticket with neither ready label is still refused.
281
281
  *
282
- * Each open agent ticket's acceptance criteria must hold no placeholders and
283
- * no untestable asks (#541, `criteriaProblems`); the spec's text isn't checked.
282
+ * Each open agent ticket's acceptance criteria must hold no placeholders, no
283
+ * untestable asks (#541), and nothing about behaviour that doesn't change
284
+ * (#653), per `criteriaProblems`; the spec's text isn't checked.
284
285
  */
285
286
  export const checkIntake = ({
286
287
  config,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alecsibilia/luca",
3
3
  "description": "Luca: turns a spec on GitHub Issues into a reviewed pull request, run from Paseo with Claude Code",
4
- "version": "14.0.0-alpha.20",
4
+ "version": "14.0.0-alpha.21",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Alec Sibilia <sibilia.alec@gmail.com>",
7
7
  "homepage": "https://github.com/asibilia/luca-framework#readme",