@exaudeus/workrail 3.70.1 → 3.70.2
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/console-ui/assets/{index-BcZJOyVG.js → index-Cr14LfsQ.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/daemon-events.d.ts +1 -1
- package/dist/daemon/workflow-runner.js +4 -2
- package/dist/manifest.json +13 -13
- package/dist/trigger/polling-scheduler.d.ts +2 -1
- package/dist/trigger/polling-scheduler.js +3 -2
- package/dist/v2/durable-core/domain/prompt-renderer.js +6 -6
- package/docs/discovery/design-review-findings.md +62 -65
- package/docs/ideas/backlog.md +222 -106
- package/docs/plans/workflow-modernization-design.md +177 -59
- package/docs/tickets/next-up.md +7 -15
- package/package.json +1 -1
- package/workflows/adaptive-ticket-creation.json +53 -18
- package/workflows/mr-review-workflow.agentic.v2.json +10 -4
package/dist/manifest.json
CHANGED
|
@@ -473,8 +473,8 @@
|
|
|
473
473
|
"sha256": "5fe866e54f796975dec5d8ba9983aefd86074db212d3fccd64eed04bc9f0b3da",
|
|
474
474
|
"bytes": 8011
|
|
475
475
|
},
|
|
476
|
-
"console-ui/assets/index-
|
|
477
|
-
"sha256": "
|
|
476
|
+
"console-ui/assets/index-Cr14LfsQ.js": {
|
|
477
|
+
"sha256": "d5ab351690b555194e079cdfe4bedcf22ac8644568d9a2b5a622d07f3451d291",
|
|
478
478
|
"bytes": 767983
|
|
479
479
|
},
|
|
480
480
|
"console-ui/assets/index-DHrKiMCf.css": {
|
|
@@ -482,7 +482,7 @@
|
|
|
482
482
|
"bytes": 60673
|
|
483
483
|
},
|
|
484
484
|
"console-ui/index.html": {
|
|
485
|
-
"sha256": "
|
|
485
|
+
"sha256": "c79189d614e1dacfc75ab3a9c4e1e030677f8730e8c2423ac45f977abd010c1a",
|
|
486
486
|
"bytes": 417
|
|
487
487
|
},
|
|
488
488
|
"console/standalone-console.d.ts": {
|
|
@@ -614,8 +614,8 @@
|
|
|
614
614
|
"bytes": 1216
|
|
615
615
|
},
|
|
616
616
|
"daemon/daemon-events.d.ts": {
|
|
617
|
-
"sha256": "
|
|
618
|
-
"bytes":
|
|
617
|
+
"sha256": "469cc9b6954e19a5eb87c3fac42f96fd66cd31321b33ce741fb9c1aa64cb2b80",
|
|
618
|
+
"bytes": 5369
|
|
619
619
|
},
|
|
620
620
|
"daemon/daemon-events.js": {
|
|
621
621
|
"sha256": "b6841eef4634bb266faf81961c1e387b535dd64a74d58582f3f2bad8c3469d95",
|
|
@@ -658,8 +658,8 @@
|
|
|
658
658
|
"bytes": 8385
|
|
659
659
|
},
|
|
660
660
|
"daemon/workflow-runner.js": {
|
|
661
|
-
"sha256": "
|
|
662
|
-
"bytes":
|
|
661
|
+
"sha256": "87e8dfbc87f2794f79b4c591eb65a204f12761e3b438174da0f81097fd1e5f4a",
|
|
662
|
+
"bytes": 103183
|
|
663
663
|
},
|
|
664
664
|
"di/container.d.ts": {
|
|
665
665
|
"sha256": "003bb7fb7478d627524b9b1e76bd0a963a243794a687ff233b96dc0e33a06d9f",
|
|
@@ -1718,12 +1718,12 @@
|
|
|
1718
1718
|
"bytes": 6968
|
|
1719
1719
|
},
|
|
1720
1720
|
"trigger/polling-scheduler.d.ts": {
|
|
1721
|
-
"sha256": "
|
|
1722
|
-
"bytes":
|
|
1721
|
+
"sha256": "c8bcd28794a23906feabe276725e63fe7af79749e0517a46c6e0ed41da0cabb2",
|
|
1722
|
+
"bytes": 1152
|
|
1723
1723
|
},
|
|
1724
1724
|
"trigger/polling-scheduler.js": {
|
|
1725
|
-
"sha256": "
|
|
1726
|
-
"bytes":
|
|
1725
|
+
"sha256": "0f8264ac6393d91e22cc48d6fb89095de2391420175009b68b5848c13be3f7f0",
|
|
1726
|
+
"bytes": 22481
|
|
1727
1727
|
},
|
|
1728
1728
|
"trigger/trigger-listener.d.ts": {
|
|
1729
1729
|
"sha256": "cbd89c24cdfe89cb555946b0dcaa6836bf81f37db56c5e80d408dc4a2fe42fb9",
|
|
@@ -2066,8 +2066,8 @@
|
|
|
2066
2066
|
"bytes": 1664
|
|
2067
2067
|
},
|
|
2068
2068
|
"v2/durable-core/domain/prompt-renderer.js": {
|
|
2069
|
-
"sha256": "
|
|
2070
|
-
"bytes":
|
|
2069
|
+
"sha256": "caff32c39ccd59219b44a5063e00e73dd29e5ba3c86a0602c2e609d17e8a0105",
|
|
2070
|
+
"bytes": 23600
|
|
2071
2071
|
},
|
|
2072
2072
|
"v2/durable-core/domain/reason-model.d.ts": {
|
|
2073
2073
|
"sha256": "a944e7e0d9b3c73468488263cb0aa1e446c023f8084fd2af53cbda3f3bfcd37a",
|
|
@@ -16,10 +16,11 @@ export declare class PollingScheduler {
|
|
|
16
16
|
private readonly router;
|
|
17
17
|
private readonly store;
|
|
18
18
|
private readonly fetchFn?;
|
|
19
|
+
private readonly sessionsDir;
|
|
19
20
|
private readonly intervals;
|
|
20
21
|
private readonly polling;
|
|
21
22
|
private readonly dispatchingIssues;
|
|
22
|
-
constructor(triggers: readonly TriggerDefinition[], router: TriggerRouter, store: PolledEventStore, fetchFn?: FetchFn | undefined);
|
|
23
|
+
constructor(triggers: readonly TriggerDefinition[], router: TriggerRouter, store: PolledEventStore, fetchFn?: FetchFn | undefined, sessionsDir?: string);
|
|
23
24
|
start(): void;
|
|
24
25
|
stop(): void;
|
|
25
26
|
forcePoll(triggerId: string): Promise<ForcePollResult>;
|
|
@@ -46,11 +46,12 @@ function isPollingTrigger(trigger) {
|
|
|
46
46
|
return trigger.pollingSource !== undefined;
|
|
47
47
|
}
|
|
48
48
|
class PollingScheduler {
|
|
49
|
-
constructor(triggers, router, store, fetchFn) {
|
|
49
|
+
constructor(triggers, router, store, fetchFn, sessionsDir = path.join(os.homedir(), '.workrail', 'daemon-sessions')) {
|
|
50
50
|
this.triggers = triggers;
|
|
51
51
|
this.router = router;
|
|
52
52
|
this.store = store;
|
|
53
53
|
this.fetchFn = fetchFn;
|
|
54
|
+
this.sessionsDir = sessionsDir;
|
|
54
55
|
this.intervals = new Map();
|
|
55
56
|
this.polling = new Map();
|
|
56
57
|
this.dispatchingIssues = new Set();
|
|
@@ -222,7 +223,7 @@ class PollingScheduler {
|
|
|
222
223
|
await appendQueuePollLog({ event: 'poll_cycle_complete', triggerId, reason: 'not_implemented', queueType: queueConfig.type, ts: new Date().toISOString() });
|
|
223
224
|
return;
|
|
224
225
|
}
|
|
225
|
-
const sessionsDir =
|
|
226
|
+
const sessionsDir = this.sessionsDir;
|
|
226
227
|
const activeSessions = await countActiveSessions(sessionsDir);
|
|
227
228
|
if (activeSessions >= queueConfig.maxTotalConcurrentSessions) {
|
|
228
229
|
console.log(`[QueuePoll] Skipping cycle: active sessions (${activeSessions}) >= maxTotalConcurrentSessions (${queueConfig.maxTotalConcurrentSessions}).`);
|
|
@@ -216,16 +216,16 @@ function buildMetricsSection(profile, isLastStep, cleanFormat) {
|
|
|
216
216
|
if (!isLastStep)
|
|
217
217
|
return shaFooter;
|
|
218
218
|
const finalFooter = cleanFormat
|
|
219
|
-
? '\n\nMetrics (final): also set metrics_outcome, metrics_pr_numbers, metrics_files_changed, metrics_lines_added, metrics_lines_removed in context.'
|
|
220
|
-
: '\n\n**METRICS (System):** This is the final step. Also report:\n- `metrics_outcome`: `"success"
|
|
219
|
+
? '\n\nMetrics (final): also set metrics_outcome (exactly one of: "success", "partial", "abandoned", "error"), metrics_pr_numbers, metrics_files_changed, metrics_lines_added, metrics_lines_removed in context.'
|
|
220
|
+
: '\n\n**METRICS (System):** This is the final step. Also report:\n- `metrics_outcome`: set to exactly one of these four strings -- no other values are valid: `"success"`, `"partial"`, `"abandoned"`, `"error"`. Do not describe what you did -- classify the outcome using only these values.\n- `metrics_pr_numbers`: array of integer PR numbers (not URLs)\n- `metrics_files_changed`: integer count\n- `metrics_lines_added`: integer count\n- `metrics_lines_removed`: integer count\n\nCall `continue_workflow` with all of the above in `context: { metrics_commit_shas: [...], metrics_outcome: "success", ... }`.';
|
|
221
221
|
return shaFooter + finalFooter;
|
|
222
222
|
}
|
|
223
223
|
case 'review': {
|
|
224
224
|
if (!isLastStep)
|
|
225
225
|
return '';
|
|
226
226
|
return cleanFormat
|
|
227
|
-
? '\n\nMetrics (final): set metrics_pr_numbers (integer array) and metrics_outcome in context.'
|
|
228
|
-
: '\n\n**METRICS (System):** This is the final step of a review workflow. Report:\n- `metrics_pr_numbers`: array of integer PR numbers reviewed (not URLs)\n- `metrics_outcome`: `"success"
|
|
227
|
+
? '\n\nMetrics (final): set metrics_pr_numbers (integer array) and metrics_outcome (exactly one of: "success", "partial", "abandoned", "error") in context.'
|
|
228
|
+
: '\n\n**METRICS (System):** This is the final step of a review workflow. Report:\n- `metrics_pr_numbers`: array of integer PR numbers reviewed (not URLs)\n- `metrics_outcome`: set to exactly one of these four strings -- no other values are valid: `"success"`, `"partial"`, `"abandoned"`, `"error"`. Do not describe what you did -- classify the outcome using only these values.\n\nCall `continue_workflow` with `context: { metrics_pr_numbers: [123], metrics_outcome: "success" }`.';
|
|
229
229
|
}
|
|
230
230
|
case 'research':
|
|
231
231
|
case 'design':
|
|
@@ -233,8 +233,8 @@ function buildMetricsSection(profile, isLastStep, cleanFormat) {
|
|
|
233
233
|
if (!isLastStep)
|
|
234
234
|
return '';
|
|
235
235
|
return cleanFormat
|
|
236
|
-
? '\n\nMetrics (final): set metrics_outcome in context.'
|
|
237
|
-
: '\n\n**METRICS (System):** This is the final step. Report:\n- `metrics_outcome`: `"success"
|
|
236
|
+
? '\n\nMetrics (final): set metrics_outcome (exactly one of: "success", "partial", "abandoned", "error") in context.'
|
|
237
|
+
: '\n\n**METRICS (System):** This is the final step. Report:\n- `metrics_outcome`: set to exactly one of these four strings -- no other values are valid: `"success"`, `"partial"`, `"abandoned"`, `"error"`. Do not describe what you did -- classify the outcome using only these values.\n\nCall `continue_workflow` with `context: { metrics_outcome: "success" }`.';
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
}
|
|
@@ -1,110 +1,107 @@
|
|
|
1
|
-
# Design Review Findings:
|
|
1
|
+
# Design Review Findings: Issue #393 Stale Tracker Close
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
**
|
|
3
|
+
**Reviewed design:** Candidate A -- Close Issue #393 with evidence comment
|
|
4
|
+
**Review date:** 2026-04-23
|
|
5
|
+
**Reviewer:** wr.discovery session (design_first / QUICK path)
|
|
5
6
|
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
## Tradeoff Review
|
|
9
10
|
|
|
10
|
-
**Tradeoff 1:
|
|
11
|
+
**Tradeoff 1: Close comment mentions why auto-close did not fire**
|
|
12
|
+
- Does not violate any decision criterion -- in fact satisfies Criterion 5 (captures the learning)
|
|
13
|
+
- Tone risk (sounds like blame): mitigated by using technical/mechanical language
|
|
14
|
+
- Hidden assumption: maintainer reads close comments -- reasonable for a 1-person repo
|
|
15
|
+
- **Verdict: Acceptable**
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
**
|
|
17
|
-
|
|
18
|
-
- A few additional context variable captures and procedure lines in Phase 0
|
|
19
|
-
- Well-framed goals produce minimal output ('goalType = problem_framed, no impliedProblem needed')
|
|
20
|
-
- **Finding: NON-ISSUE.** Overhead is trivial.
|
|
21
|
-
|
|
22
|
-
**Tradeoff 3: Phase 1g always-on for design_first/full_spectrum**
|
|
23
|
-
|
|
24
|
-
- One additional advance per session for these paths
|
|
25
|
-
- Produces trivially short output for well-framed sessions ('pathChangedAfterContext = false')
|
|
26
|
-
- **CRITICAL CORRECTION NEEDED:** Phase 1g runCondition must be an OR (`retriageNeeded = true OR pathRecommendation in [design_first, full_spectrum]`) not a replacement. Otherwise landscape_first sessions that explicitly need retriage will not trigger it.
|
|
27
|
-
- **Finding: YELLOW.** Runnable as-designed if the OR condition is used correctly.
|
|
17
|
+
**Tradeoff 2: No AGENTS.md update -- pattern prevention sacrificed**
|
|
18
|
+
- Actively satisfies Criterion 3 (no new problems) by not touching a protected human-maintained file
|
|
19
|
+
- Only one observed instance of the failure mode (PR #790) -- insufficient evidence of a recurring pattern
|
|
20
|
+
- The learning is captured in the close comment itself, which is more contextually located than AGENTS.md
|
|
21
|
+
- **Verdict: Acceptable**
|
|
28
22
|
|
|
29
23
|
---
|
|
30
24
|
|
|
31
25
|
## Failure Mode Review
|
|
32
26
|
|
|
33
|
-
**
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
27
|
+
**FM1: Maintainer re-opens because they wanted to close personally**
|
|
28
|
+
- Design handles it: close comment provides full evidence chain; re-open is 5-second CLI command; no data loss
|
|
29
|
+
- Likelihood: Low (0 comments, 2-day stale, daemon assignee, no checkbox activity)
|
|
30
|
+
- Severity if occurs: Minimal (issue re-opens, maintainer closes manually, traceability comment persists)
|
|
31
|
+
- Missing mitigations: None needed
|
|
37
32
|
|
|
38
|
-
**
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
**Failure mode 3: Phase 1g doesn't surface new insights for well-framed sessions**
|
|
44
|
-
- Status: **Non-issue by design.** For well-framed sessions, Phase 1g is a graceful no-op that confirms the path is still correct. One advance wasted, nothing more.
|
|
45
|
-
- **Finding: LOW risk, acceptable.**
|
|
33
|
+
**FM2: CI secretly failing for the test file**
|
|
34
|
+
- Design handles it: 14/14 passing verified locally immediately before action; test is isolated unit coverage
|
|
35
|
+
- No related CI failure issues exist in the open issues list for this test file
|
|
36
|
+
- Severity if occurs: Low (tracker close is orthogonal to CI state; no test regression introduced)
|
|
37
|
+
- Missing mitigations: None needed
|
|
46
38
|
|
|
47
39
|
---
|
|
48
40
|
|
|
49
41
|
## Runner-Up / Simpler Alternative Review
|
|
50
42
|
|
|
51
|
-
**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
**`alternativeFraming` addition from C2:** Borrowing C2's `alternativeFraming` requirement (one reframe even when the original goal seems correct) is high-value, low-cost. Add to Phase 0 design doc entry, not as a context variable.
|
|
43
|
+
**Runner-up (Candidate B -- close + AGENTS.md note):**
|
|
44
|
+
- Candidate B's only distinct value (keyword failure mode documentation) is fully absorbed into Candidate A's close comment
|
|
45
|
+
- No element of B is orphaned; no hybrid needed
|
|
56
46
|
|
|
57
|
-
**
|
|
47
|
+
**Simpler variant (close without comment):**
|
|
48
|
+
- Fails Criterion 2 (no traceability) and Criterion 5 (no learning capture)
|
|
49
|
+
- Not viable -- the comment is load-bearing, not decorative
|
|
58
50
|
|
|
59
51
|
---
|
|
60
52
|
|
|
61
53
|
## Philosophy Alignment
|
|
62
54
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
| Determinism over cleverness | SATISFIED -- same goalType input produces same path behavior |
|
|
55
|
+
**Clearly satisfied:**
|
|
56
|
+
- Validate at boundaries, trust inside -- all validation done before action
|
|
57
|
+
- Observability -- close comment makes the state transition and rationale fully visible
|
|
58
|
+
- Document "why" not "what" -- comment explains rationale, not just action
|
|
59
|
+
- Atomicity -- single CLI call, no partial state possible
|
|
60
|
+
- Architectural fixes over patches -- reframe correctly identified the real problem (stale tracker) before acting
|
|
70
61
|
|
|
71
|
-
**
|
|
62
|
+
**Under tension:**
|
|
63
|
+
- Agent authority over human-filed issues -- mild tension; resolved by reversibility + transparent comment
|
|
64
|
+
- **Verdict: Acceptable tension, not risky**
|
|
72
65
|
|
|
73
66
|
---
|
|
74
67
|
|
|
75
68
|
## Findings
|
|
76
69
|
|
|
77
|
-
|
|
70
|
+
No RED or ORANGE findings. All challenges and reviews converge.
|
|
78
71
|
|
|
79
|
-
**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
The retriage step runCondition must be: `retriageNeeded = true OR pathRecommendation == design_first OR pathRecommendation == full_spectrum`. A straight replacement would break landscape_first sessions that legitimately need retriage.
|
|
84
|
-
|
|
85
|
-
**Y3: 'What would make this framing wrong' needs specificity instruction**
|
|
86
|
-
The required output field should specify 'name ONE concrete falsification condition, not a general caveat.' Without this, the field can be satisfied by formulaic responses.
|
|
87
|
-
|
|
88
|
-
### No Red or Orange findings
|
|
89
|
-
|
|
90
|
-
The selected C1+C3 direction has no material structural weaknesses.
|
|
72
|
+
**YELLOW -- Tone of close comment (INFO)**
|
|
73
|
+
- Risk: the explanation of why auto-close did not fire could read as attributing a mistake to the PR author
|
|
74
|
+
- Mitigation: use mechanical/technical language ("GitHub requires `Closes #NNN` syntax; PR #790 used different phrasing") rather than evaluative language
|
|
75
|
+
- Action: word the comment accordingly -- no structural change to the design needed
|
|
91
76
|
|
|
92
77
|
---
|
|
93
78
|
|
|
94
79
|
## Recommended Revisions
|
|
95
80
|
|
|
96
|
-
|
|
81
|
+
**Revision 1 (from YELLOW finding): Prescribe exact comment wording**
|
|
97
82
|
|
|
98
|
-
|
|
83
|
+
Use this comment text:
|
|
99
84
|
|
|
100
|
-
|
|
85
|
+
> All acceptance criteria for this issue are satisfied on `main`.
|
|
86
|
+
>
|
|
87
|
+
> - `loadSessionNotes` is exported at `src/daemon/workflow-runner.ts` (added in PR #790)
|
|
88
|
+
> - All 4 failure paths (token decode, store load, projection, unexpected exception) and the happy path are covered by `tests/unit/workflow-runner-load-session-notes.test.ts` (added in PR #782)
|
|
89
|
+
> - 14 tests pass: `npx vitest run tests/unit/workflow-runner-load-session-notes.test.ts`
|
|
90
|
+
>
|
|
91
|
+
> Note: PR #790 referenced this issue as "Closes issue #393 pre-existing test failures" but GitHub's auto-close requires the exact syntax `Closes #393` -- the non-standard phrasing is why the issue was not automatically closed on merge.
|
|
101
92
|
|
|
102
|
-
|
|
93
|
+
This wording is factual, neutral, and gives any future reader everything they need to verify or re-open.
|
|
103
94
|
|
|
104
95
|
---
|
|
105
96
|
|
|
106
97
|
## Residual Concerns
|
|
107
98
|
|
|
108
|
-
|
|
99
|
+
**RC1 (low): Pattern recurrence unaddressed**
|
|
100
|
+
If the PR keyword failure mode recurs on a second PR, the case for Candidate B (AGENTS.md note) strengthens. This is not actionable now but should be noted for future monitoring.
|
|
101
|
+
|
|
102
|
+
**RC2 (very low): Open CI failures on main**
|
|
103
|
+
There are 10+ open "CI failure on main blocking release" issues. These are unrelated to the test file in question (verified locally). If main CI is broken in a way that affects this test file, the close would be slightly premature. Probability is very low given local verification.
|
|
104
|
+
|
|
105
|
+
---
|
|
109
106
|
|
|
110
|
-
|
|
107
|
+
**Overall verdict: PROCEED with Candidate A as designed, using the prescribed comment wording from Revision 1.**
|