dev-loops 0.1.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/.pi/dev-loop/defaults.yaml +477 -0
- package/AGENTS.md +25 -0
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/agents/dev-loop.agent.md +82 -0
- package/agents/developer.agent.md +37 -0
- package/agents/docs.agent.md +33 -0
- package/agents/fixer.agent.md +53 -0
- package/agents/quality.agent.md +28 -0
- package/agents/refiner.agent.md +87 -0
- package/agents/review.agent.md +64 -0
- package/cli/index.mjs +424 -0
- package/extension/README.md +233 -0
- package/extension/checks.ts +94 -0
- package/extension/index.ts +131 -0
- package/extension/post-merge-update.ts +512 -0
- package/extension/presentation.ts +107 -0
- package/lib/dev-loops-core.mjs +284 -0
- package/package.json +103 -0
- package/scripts/README.md +1007 -0
- package/scripts/_cli-primitives.mjs +10 -0
- package/scripts/_core-helpers.mjs +30 -0
- package/scripts/docs/validate-links.mjs +567 -0
- package/scripts/docs/validate-no-duplicate-rules.mjs +250 -0
- package/scripts/github/_review-thread-mutations.mjs +214 -0
- package/scripts/github/capture-review-threads.mjs +180 -0
- package/scripts/github/create-draft-pr.mjs +108 -0
- package/scripts/github/detect-checkpoint-evidence.mjs +393 -0
- package/scripts/github/detect-linked-issue-pr.mjs +331 -0
- package/scripts/github/manage-sub-issues.mjs +394 -0
- package/scripts/github/probe-copilot-review.mjs +323 -0
- package/scripts/github/ready-for-review.mjs +93 -0
- package/scripts/github/reconcile-draft-gate.mjs +328 -0
- package/scripts/github/reply-resolve-review-thread.mjs +42 -0
- package/scripts/github/reply-resolve-review-threads.mjs +329 -0
- package/scripts/github/request-copilot-review.mjs +551 -0
- package/scripts/github/resolve-tracker-local-spec.mjs +205 -0
- package/scripts/github/stage-reviewer-draft.mjs +191 -0
- package/scripts/github/upsert-checkpoint-verdict.mjs +694 -0
- package/scripts/github/verify-fresh-review-context.mjs +125 -0
- package/scripts/github/write-gate-findings-log.mjs +212 -0
- package/scripts/loop/_checkpoint-io.mjs +55 -0
- package/scripts/loop/_checkpoint-paths.mjs +28 -0
- package/scripts/loop/_handoff-contract.mjs +230 -0
- package/scripts/loop/_inspect-run-viewer-adapter.mjs +345 -0
- package/scripts/loop/_loop-evidence.mjs +32 -0
- package/scripts/loop/_pr-runner-coordination.mjs +611 -0
- package/scripts/loop/_stale-runner-detection.mjs +145 -0
- package/scripts/loop/_steering-state-file.mjs +134 -0
- package/scripts/loop/build-handoff-envelope.mjs +181 -0
- package/scripts/loop/checkpoint-contract.mjs +49 -0
- package/scripts/loop/conductor-monitor.mjs +1850 -0
- package/scripts/loop/conductor.mjs +214 -0
- package/scripts/loop/copilot-pr-handoff.mjs +493 -0
- package/scripts/loop/debt-remediate.mjs +304 -0
- package/scripts/loop/detect-change-scope.mjs +102 -0
- package/scripts/loop/detect-copilot-loop-state.mjs +454 -0
- package/scripts/loop/detect-copilot-session-activity.mjs +186 -0
- package/scripts/loop/detect-initial-copilot-pr-state.mjs +318 -0
- package/scripts/loop/detect-internal-only-pr.mjs +270 -0
- package/scripts/loop/detect-issue-refinement-artifact.mjs +163 -0
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +509 -0
- package/scripts/loop/detect-reviewer-loop-state.mjs +231 -0
- package/scripts/loop/detect-stale-runner.mjs +250 -0
- package/scripts/loop/detect-tracker-first-loop-state.mjs +76 -0
- package/scripts/loop/detect-tracker-pr-state.mjs +102 -0
- package/scripts/loop/info.mjs +267 -0
- package/scripts/loop/inspect-run-viewer/cli.mjs +117 -0
- package/scripts/loop/inspect-run-viewer/constants.mjs +80 -0
- package/scripts/loop/inspect-run-viewer/graph.mjs +757 -0
- package/scripts/loop/inspect-run-viewer/handoff-envelope-renderer.mjs +398 -0
- package/scripts/loop/inspect-run-viewer/inbox.mjs +308 -0
- package/scripts/loop/inspect-run-viewer/managed-instance.mjs +750 -0
- package/scripts/loop/inspect-run-viewer/rendering.mjs +411 -0
- package/scripts/loop/inspect-run-viewer/server.mjs +638 -0
- package/scripts/loop/inspect-run-viewer/shared.mjs +103 -0
- package/scripts/loop/inspect-run-viewer/status.mjs +715 -0
- package/scripts/loop/inspect-run-viewer-ci-changes.mjs +77 -0
- package/scripts/loop/inspect-run-viewer.mjs +82 -0
- package/scripts/loop/inspect-run.mjs +382 -0
- package/scripts/loop/outer-loop.mjs +419 -0
- package/scripts/loop/pr-runner-coordination.mjs +143 -0
- package/scripts/loop/pre-commit-branch-guard.mjs +68 -0
- package/scripts/loop/pre-flight-gate.mjs +236 -0
- package/scripts/loop/pre-pr-ready-gate.mjs +183 -0
- package/scripts/loop/pre-push-main-guard.mjs +103 -0
- package/scripts/loop/pre-write-remote-freshness-guard.mjs +32 -0
- package/scripts/loop/print-gates.mjs +42 -0
- package/scripts/loop/resolve-dev-loop-startup.mjs +533 -0
- package/scripts/loop/run-conductor-cycle.mjs +322 -0
- package/scripts/loop/run-queue.mjs +124 -0
- package/scripts/loop/run-refinement-audit.mjs +513 -0
- package/scripts/loop/run-watch-cycle.mjs +358 -0
- package/scripts/loop/steer-loop.mjs +841 -0
- package/scripts/loop/ui-designer-review-contract.mjs +76 -0
- package/scripts/loop/watch-initial-copilot-pr.mjs +253 -0
- package/scripts/projects/add-queue-item.mjs +528 -0
- package/scripts/projects/ensure-queue-board.mjs +837 -0
- package/scripts/projects/list-queue-items.mjs +489 -0
- package/scripts/projects/move-queue-item.mjs +549 -0
- package/scripts/projects/reorder-queue-item.mjs +518 -0
- package/scripts/refine/_refine-helpers.mjs +258 -0
- package/scripts/refine/prose-linkage-detector.mjs +92 -0
- package/scripts/refine/refinement-completeness-checker.mjs +88 -0
- package/scripts/refine/scope-boundary-cross-checker.mjs +163 -0
- package/scripts/refine/tree-integrity-validator.mjs +211 -0
- package/scripts/refine/verify.mjs +178 -0
- package/scripts/repo-wiki-local.mjs +156 -0
- package/scripts/repo-wiki.mjs +119 -0
- package/skills/copilot-pr-followup/SKILL.md +380 -0
- package/skills/dev-loop/SKILL.md +141 -0
- package/skills/dev-loop/scripts/dev-mode-context.mjs +152 -0
- package/skills/dev-loop/scripts/dev-mode-context.test.mjs +80 -0
- package/skills/dev-loop/scripts/init-phase.mjs +71 -0
- package/skills/dev-loop/scripts/log-bash-exit-1.mjs +25 -0
- package/skills/dev-loop/scripts/phase-files.mjs +29 -0
- package/skills/dev-loop/scripts/post-gate-verdict-fallback.mjs +480 -0
- package/skills/dev-loop/scripts/post-gate-verdict-fallback.test.mjs +732 -0
- package/skills/dev-loop/scripts/render-template.mjs +82 -0
- package/skills/dev-loop/scripts/render-template.test.mjs +63 -0
- package/skills/dev-loop/templates/bootstrap-agents.md +26 -0
- package/skills/dev-loop/templates/bootstrap-implementation-state.md +31 -0
- package/skills/dev-loop/templates/bootstrap-implementation-workflow.md +17 -0
- package/skills/dev-loop/templates/dev-mode-retrospective.md +15 -0
- package/skills/dev-loop/templates/dev-mode-review.md +17 -0
- package/skills/dev-loop/templates/dev-mode-skill-changes.md +11 -0
- package/skills/dev-loop/templates/merged-phase-plan.md +19 -0
- package/skills/dev-loop/templates/phase-doc.md +27 -0
- package/skills/dev-loop/templates/phase-summary.md +13 -0
- package/skills/dev-loop/templates/phase-variant.md +15 -0
- package/skills/dev-loop/templates/retrospective.md +11 -0
- package/skills/dev-loop/templates/review.md +32 -0
- package/skills/dev-loop/templates/ui-vision-review.md +55 -0
- package/skills/docs/acceptance-criteria-verification.md +21 -0
- package/skills/docs/anti-patterns.md +21 -0
- package/skills/docs/artifact-authority-contract.md +119 -0
- package/skills/docs/confirmation-rules.md +28 -0
- package/skills/docs/copilot-ci-status-contract.md +52 -0
- package/skills/docs/copilot-loop-operations.md +233 -0
- package/skills/docs/debt-remediation-contract.md +107 -0
- package/skills/docs/entrypoint-strategies.md +115 -0
- package/skills/docs/epic-tree-refinement-procedure.md +234 -0
- package/skills/docs/issue-intake-procedure.md +235 -0
- package/skills/docs/main-agent-contract.md +72 -0
- package/skills/docs/merge-preconditions.md +29 -0
- package/skills/docs/pr-lifecycle-contract.md +209 -0
- package/skills/docs/public-dev-loop-contract.md +497 -0
- package/skills/docs/retrospective-checkpoint-contract.md +159 -0
- package/skills/docs/stop-conditions.md +29 -0
- package/skills/docs/structural-quality.md +42 -0
- package/skills/docs/tracker-first-loop-state.md +281 -0
- package/skills/docs/validation-policy.md +27 -0
- package/skills/docs/workflow-handoff-contract.md +135 -0
- package/skills/final-approval/SKILL.md +19 -0
- package/skills/local-implementation/SKILL.md +640 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Stop conditions
|
|
2
|
+
|
|
3
|
+
Canonical owner for agent stop / wait / block conditions across all workflow families.
|
|
4
|
+
|
|
5
|
+
## Genuine stop conditions
|
|
6
|
+
|
|
7
|
+
| Condition | Strategy | Behavior |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `blocked` lifecycle state | all | Stop for human decision |
|
|
10
|
+
| `done` lifecycle state | all | Terminal stop |
|
|
11
|
+
| `approval_ready` without explicit merge auth | `final_approval` | Stop at approval gate |
|
|
12
|
+
| `merge_ready` without explicit merge auth | all | Stop at `waiting_for_merge_authorization` |
|
|
13
|
+
| Ambiguous / contradictory state | all | Fail closed to `needs_reconcile` |
|
|
14
|
+
| Missing authoritative startup inputs | `dev-loop` | Fail closed |
|
|
15
|
+
|
|
16
|
+
## Non-stop conditions
|
|
17
|
+
|
|
18
|
+
| Condition | Strategy | Behavior |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `waiting` lifecycle state | `wait_watch` | Healthy wait; re-dispatch from main session |
|
|
21
|
+
| `waiting_for_initial_copilot_implementation` | `issue_intake` | Bootstrap wait with 1h watch budget |
|
|
22
|
+
| `waiting_for_copilot_review` | `copilot_pr_followup` | Continuation boundary, not completion |
|
|
23
|
+
| Quiet watcher observations | `wait_watch` | Observational only, do not surface |
|
|
24
|
+
|
|
25
|
+
## Cross-references
|
|
26
|
+
|
|
27
|
+
- [Confirmation rules](confirmation-rules.md)
|
|
28
|
+
- [Merge preconditions](merge-preconditions.md)
|
|
29
|
+
- [Public Dev Loop Contract](public-dev-loop-contract.md)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Structural quality
|
|
2
|
+
|
|
3
|
+
Canonical owner for structural quality standards across all workflow families.
|
|
4
|
+
|
|
5
|
+
## Core principles
|
|
6
|
+
|
|
7
|
+
- **KISS**: Keep implementations simple; prefer thin glue over thick abstraction
|
|
8
|
+
- **SRP**: Single Responsibility Principle — one reason to change per module
|
|
9
|
+
- **YAGNI**: Don't add speculative features, compatibility shims, or unused abstractions
|
|
10
|
+
- **Strict TypeScript**: No `any`, no implicit coercion, explicit return types
|
|
11
|
+
|
|
12
|
+
## Deep review standards
|
|
13
|
+
|
|
14
|
+
Apply these during implementation (not just review):
|
|
15
|
+
|
|
16
|
+
1. **Cohesion**: Related functionality lives together; unrelated functionality is separated
|
|
17
|
+
2. **Coupling**: Minimize dependencies between modules; prefer explicit injection over globals
|
|
18
|
+
3. **Error handling**: All error paths are explicit and tested; no silent failures
|
|
19
|
+
4. **Testability**: Every public function is independently testable; no hidden state
|
|
20
|
+
5. **Naming**: Names describe what, not how; consistent vocabulary across codebase
|
|
21
|
+
|
|
22
|
+
## Implementation self-check rules
|
|
23
|
+
|
|
24
|
+
Apply these during implementation (not just at review time):
|
|
25
|
+
|
|
26
|
+
- **Prefer deletion over addition**: Question every new file, export, layer, and moving part. If it does not earn its keep, remove it.
|
|
27
|
+
- **File size ceiling**: Files over ~1k lines need extraction or an explicit justification kept in a code comment or doc reference.
|
|
28
|
+
- **Logic placement**: Do not bolt conditionals onto unrelated paths; push logic into its own dedicated boundary.
|
|
29
|
+
- **Avoid thin abstractions**: No thin wrappers, re-export-only files, or identity abstractions that add indirection without clarity.
|
|
30
|
+
- **No leaky abstractions**: Do not leak feature-specific logic into shared or general-purpose modules.
|
|
31
|
+
|
|
32
|
+
## Anti-patterns to avoid
|
|
33
|
+
|
|
34
|
+
- Over-engineering: adding abstraction layers "just in case"
|
|
35
|
+
- Copy-paste duplication: extracting shared logic too late
|
|
36
|
+
- Magic values: undocumented constants or configuration
|
|
37
|
+
- God modules: single file doing too many unrelated things
|
|
38
|
+
|
|
39
|
+
## Cross-references
|
|
40
|
+
|
|
41
|
+
- [Anti-patterns](anti-patterns.md)
|
|
42
|
+
- [Validation policy](validation-policy.md)
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Tracker-First Story-to-PR Contract
|
|
2
|
+
|
|
3
|
+
This document defines the adapter-agnostic MVP contract for the tracker-first
|
|
4
|
+
story-to-PR workflow in `pi-dev-loops`.
|
|
5
|
+
|
|
6
|
+
**MVP invariant: one tracker work item → one GitHub PR.**
|
|
7
|
+
|
|
8
|
+
This document serves dual purpose:
|
|
9
|
+
1. **Story-to-PR contract** — canonical for the PR-level tracker state machine
|
|
10
|
+
2. **Loop state machine doc** — canonical for the tracker-first loop state machine (#449)
|
|
11
|
+
|
|
12
|
+
Implementation for each:
|
|
13
|
+
|
|
14
|
+
| Component | File |
|
|
15
|
+
|---|---|
|
|
16
|
+
| PR-level state machine (story-to-PR) | `packages/core/src/loop/tracker-pr-state.mjs` |
|
|
17
|
+
| PR-level CLI detector | `scripts/loop/detect-tracker-pr-state.mjs` |
|
|
18
|
+
| Loop state machine (tracker-first) | `packages/core/src/loop/tracker-first-loop-state.mjs` |
|
|
19
|
+
| Loop state CLI detector | `scripts/loop/detect-tracker-first-loop-state.mjs` |
|
|
20
|
+
| Loop state contract doc | this file |
|
|
21
|
+
| Entrypoint briefing | `skills/docs/entrypoint-strategies.md#tracker-first` |
|
|
22
|
+
|
|
23
|
+
## 1. Artifact Subset and MVP Invariant
|
|
24
|
+
|
|
25
|
+
| Artifact | Role in this slice |
|
|
26
|
+
|---|---|
|
|
27
|
+
| One tracker work item (story, task, or bug) | Planning artifact; source of truth for work identity and planning state |
|
|
28
|
+
| One GitHub PR | Execution artifact; source of truth for lifecycle, review, CI, and merge facts |
|
|
29
|
+
| PR review / CI / merge facts | Observable from GitHub; feed reverse-sync decisions |
|
|
30
|
+
| Epic / PRD reference | Optional linked metadata only; no roll-up or automation in this slice |
|
|
31
|
+
| ADR / RFC reference | Optional linked metadata only; no decision-sync in this slice |
|
|
32
|
+
|
|
33
|
+
**Invariant:** For any single tracker work item in scope, there is at most
|
|
34
|
+
one active GitHub PR at a time. Multi-PR workflows and roll-up automation
|
|
35
|
+
are out of scope for this slice.
|
|
36
|
+
|
|
37
|
+
## 2. Source-of-Truth Ownership
|
|
38
|
+
|
|
39
|
+
| Domain | Owner | Examples |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| Work-item identity and planning hierarchy | Tracker | Item ID, title, description, priority, assignee, epic link |
|
|
42
|
+
| Tracker-native workflow state | Tracker | In-progress, blocked, done/completed, and any tracker-specific sub-states |
|
|
43
|
+
| PR lifecycle facts | GitHub | Draft / ready-for-review, open / merged / closed, branch, head SHA |
|
|
44
|
+
| PR review and CI facts | GitHub | Reviewer assignments, review states, check-run results, merge status |
|
|
45
|
+
| Decision content | ADR / RFC artifacts (when linked) | Architecture decisions and RFCs referenced from PR body |
|
|
46
|
+
| PR projection and reverse-sync logic | `pi-dev-loops` | Title/body/label generation rules, state mapping, sync triggers |
|
|
47
|
+
|
|
48
|
+
`pi-dev-loops` **does not** become the canonical owner of any business fields.
|
|
49
|
+
It provides projection and sync logic only.
|
|
50
|
+
|
|
51
|
+
## 3. PR Projection Contract
|
|
52
|
+
|
|
53
|
+
The following rules define how a tracker work item projects into GitHub PR
|
|
54
|
+
metadata. All rules are deterministic and idempotent: applying them to the
|
|
55
|
+
same inputs always produces the same output, and re-applying them to an
|
|
56
|
+
already-correct PR leaves it unchanged.
|
|
57
|
+
|
|
58
|
+
### 3.1 Required PR Metadata
|
|
59
|
+
|
|
60
|
+
| Field | Rule |
|
|
61
|
+
|---|---|
|
|
62
|
+
| PR title | `[{TRACKER_ID}] {tracker item title}` — bracketed tracker identifier followed by the item title verbatim |
|
|
63
|
+
| PR body — Tracker section | Required. Must include the tracker item ID and a direct link to the item. |
|
|
64
|
+
| PR body — Summary section | Required. Brief description of the change implemented in this PR. |
|
|
65
|
+
| PR body — Acceptance Criteria section | Required. Copied or linked from the tracker item's acceptance criteria. |
|
|
66
|
+
| Labels | Required: `tracker:{TRACKER_ID}`. Optional reference labels: `epic:{EPIC_ID}`, `prd:{PRD_ID}` when references are present. |
|
|
67
|
+
| Draft state | PR must start as a draft. It must not be marked ready-for-review until development work is complete. |
|
|
68
|
+
|
|
69
|
+
### 3.2 Optional Reference Metadata
|
|
70
|
+
|
|
71
|
+
Optional parent / decision references may appear in the PR body as links only.
|
|
72
|
+
They are read-only metadata in this slice and do not trigger any automation:
|
|
73
|
+
|
|
74
|
+
| Reference type | Placement | Effect |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Epic | PR body — References section | Link only; no roll-up automation |
|
|
77
|
+
| PRD | PR body — References section | Link only; no roll-up automation |
|
|
78
|
+
| ADR | PR body — References section | Link only; no decision sync |
|
|
79
|
+
| RFC | PR body — References section | Link only; no decision sync |
|
|
80
|
+
|
|
81
|
+
### 3.3 Deterministic Update Rules
|
|
82
|
+
|
|
83
|
+
1. **On PR create**: Generate title, body, and labels from tracker item fields.
|
|
84
|
+
Apply draft state.
|
|
85
|
+
2. **On tracker item field change**: Re-apply projection rules to PR title,
|
|
86
|
+
body, and labels. Leave any sections not covered by projection rules
|
|
87
|
+
(e.g. reviewer-added review comments) intact.
|
|
88
|
+
3. **Idempotent regeneration**: If the PR already has the correct title, body
|
|
89
|
+
sections, and labels, no mutation is performed. Projection is a no-op
|
|
90
|
+
when the current state already matches the target.
|
|
91
|
+
|
|
92
|
+
### 3.4 PR Body Template
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
## Summary
|
|
96
|
+
{brief description of the change}
|
|
97
|
+
|
|
98
|
+
## Acceptance Criteria
|
|
99
|
+
{copied or linked from tracker item}
|
|
100
|
+
|
|
101
|
+
## Tracker
|
|
102
|
+
- Item: [{TRACKER_ID}]({TRACKER_ITEM_URL})
|
|
103
|
+
|
|
104
|
+
## References
|
|
105
|
+
<!-- optional; add epic/PRD/ADR/RFC links here as plain links only -->
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 4. Reverse-Sync Contract
|
|
109
|
+
|
|
110
|
+
The following table defines the canonical reverse-sync contract. Adapter
|
|
111
|
+
implementations map canonical action names to tracker-native field updates.
|
|
112
|
+
|
|
113
|
+
### 4.1 Canonical State Table
|
|
114
|
+
|
|
115
|
+
| Lifecycle state | `reverseSyncAction` | Tracker effect |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `ready_no_pr` — tracker item exists, no PR exists yet | `none` | No automatic mutation. Tracker-native readiness remains tracker-owned and is outside this snapshot-only helper. |
|
|
118
|
+
| `draft_pr_open` — draft PR created or open | `set_in_progress` | Tracker moves to in-progress (or nearest equivalent) |
|
|
119
|
+
| `pr_reviewable` — PR marked ready for review | `set_reviewable` | Tracker moves to reviewable / in-review (or nearest equivalent) |
|
|
120
|
+
| `pr_merged` — PR merged | `set_done` | Tracker moves to done/completed terminal state |
|
|
121
|
+
| `pr_closed_unmerged` — PR closed without merge | `none` | No automatic terminal transition; human decision required |
|
|
122
|
+
| `no_tracker_item` | `none` | No tracker item to update |
|
|
123
|
+
| `blocked_needs_user_decision` | `none` | Stop and report; no automatic tracker update |
|
|
124
|
+
|
|
125
|
+
### 4.2 Event Triggers
|
|
126
|
+
|
|
127
|
+
| PR lifecycle event | Maps to canonical state | Sync trigger |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| No PR created yet | `ready_no_pr` | No trigger |
|
|
130
|
+
| Draft PR creation succeeds | `draft_pr_open` | Apply `set_in_progress` to tracker |
|
|
131
|
+
| PR converted from draft to ready-for-review | `pr_reviewable` | Apply `set_reviewable` to tracker |
|
|
132
|
+
| PR merged | `pr_merged` | Apply `set_done` to tracker |
|
|
133
|
+
| PR closed without merge | `pr_closed_unmerged` | No automatic sync; report to user |
|
|
134
|
+
|
|
135
|
+
### 4.3 Adapter Mapping Guidance
|
|
136
|
+
|
|
137
|
+
Each tracker adapter maps the four canonical action names to its native API:
|
|
138
|
+
|
|
139
|
+
| Canonical action | Adapter responsibility |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `set_in_progress` | Move item to the adapter's in-progress equivalent (e.g. "In Progress" column, status field, or state transition) |
|
|
142
|
+
| `set_reviewable` | Move item to the adapter's in-review / reviewable equivalent |
|
|
143
|
+
| `set_done` | Move item to the adapter's done/completed terminal state |
|
|
144
|
+
| `none` | No tracker mutation |
|
|
145
|
+
|
|
146
|
+
## 5. State Machine
|
|
147
|
+
|
|
148
|
+
The full lifecycle path for this MVP slice is:
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
selected/ready (tracker-owned precondition; not encoded directly in this snapshot)
|
|
152
|
+
-> tracker item exists, no PR [ready_no_pr]
|
|
153
|
+
-> draft PR created [draft_pr_open] -> tracker: set_in_progress
|
|
154
|
+
-> PR marked ready for review [pr_reviewable] -> tracker: set_reviewable
|
|
155
|
+
-> PR merged [pr_merged] -> tracker: set_done
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Alternate paths:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
PR closed without merge [pr_closed_unmerged] -> tracker: no automatic action
|
|
162
|
+
No tracker item, no PR [no_tracker_item] -> blocked; report and stop
|
|
163
|
+
Contradictory snapshot [blocked_needs_user_decision] -> stop and report
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 5.1 State Definitions
|
|
167
|
+
|
|
168
|
+
| State | Meaning |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `no_tracker_item` | No tracker work item was found; lifecycle cannot proceed |
|
|
171
|
+
| `ready_no_pr` | Tracker item exists and no PR has been created yet. This helper does not infer tracker-native readiness beyond that no-PR fact. |
|
|
172
|
+
| `draft_pr_open` | Draft PR exists; tracker should reflect in-progress |
|
|
173
|
+
| `pr_reviewable` | PR is open and not draft; tracker should reflect reviewable / in-review |
|
|
174
|
+
| `pr_merged` | PR has been merged; tracker should be moved to done/completed |
|
|
175
|
+
| `pr_closed_unmerged` | PR was closed without merge; no automatic tracker transition |
|
|
176
|
+
| `blocked_needs_user_decision` | Unexpected or contradictory state; requires explicit user decision |
|
|
177
|
+
|
|
178
|
+
### 5.2 Transition Graph
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
no_tracker_item
|
|
182
|
+
(no transitions — obtain a valid tracker item first)
|
|
183
|
+
|
|
184
|
+
ready_no_pr
|
|
185
|
+
-> draft_pr_open (create a draft PR with required tracker metadata)
|
|
186
|
+
|
|
187
|
+
draft_pr_open
|
|
188
|
+
-> pr_reviewable (mark the PR as ready for review)
|
|
189
|
+
|
|
190
|
+
pr_reviewable
|
|
191
|
+
-> pr_merged (PR is merged)
|
|
192
|
+
-> pr_closed_unmerged (PR is closed without merge)
|
|
193
|
+
-> draft_pr_open (convert back to draft if rework is needed)
|
|
194
|
+
|
|
195
|
+
pr_merged
|
|
196
|
+
(no transitions — terminal success state)
|
|
197
|
+
|
|
198
|
+
pr_closed_unmerged
|
|
199
|
+
-> ready_no_pr (reopen work; create a new PR)
|
|
200
|
+
-> blocked_needs_user_decision (escalate if context is unclear)
|
|
201
|
+
|
|
202
|
+
blocked_needs_user_decision
|
|
203
|
+
(no transitions — stop and report; await explicit user authorization)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 5.3 Snapshot Schema
|
|
207
|
+
|
|
208
|
+
| Field | Type | Description |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `trackerItemExists` | `boolean` | Whether a tracker work item was found |
|
|
211
|
+
| `trackerItemId` | `string \| null` | Opaque tracker item identifier (e.g. `"PROJ-123"`) |
|
|
212
|
+
| `prExists` | `boolean` | Whether a GitHub PR exists for this tracker item |
|
|
213
|
+
| `prNumber` | `number \| null` | PR number if known. Canonical no-PR snapshots should set this to `null`; `prNumber` with `prExists=false` is treated as contradictory and blocked. |
|
|
214
|
+
| `prDraft` | `boolean` | Whether the PR is in draft state |
|
|
215
|
+
| `prMerged` | `boolean` | Whether the PR has been merged |
|
|
216
|
+
| `prClosed` | `boolean` | Whether the PR is closed on GitHub. Merged PRs are also closed, so `pr_closed_unmerged` is derived from `prClosed && !prMerged`. |
|
|
217
|
+
|
|
218
|
+
Unlike the Copilot/reviewer loop snapshots, this tracker contract uses `prClosed` for the raw GitHub closed state. Merged PRs therefore set both `prMerged=true` and `prClosed=true`, while `pr_closed_unmerged` remains the derived terminal state for `prClosed && !prMerged`.
|
|
219
|
+
|
|
220
|
+
This snapshot intentionally omits tracker-native workflow fields such as selected/ready, blocked, or done. Higher-level callers must combine tracker-owned readiness/state separately when deciding whether opening a PR is appropriate.
|
|
221
|
+
|
|
222
|
+
## 6. Scope Boundaries
|
|
223
|
+
|
|
224
|
+
This contract is intentionally narrower than the parent epics:
|
|
225
|
+
|
|
226
|
+
| Boundary | In scope (this slice) | Out of scope (deferred) |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| Tracker adapters | Adapter-agnostic contract only | Jira adapter, Shortcut adapter, any specific adapter |
|
|
229
|
+
| Artifact model | One tracker item + one PR | Multi-PR, roll-up, cross-artifact sync |
|
|
230
|
+
| Epic / PRD | Metadata reference links only | Automated roll-up or field sync |
|
|
231
|
+
| ADR / RFC | Metadata reference links only | Decision synchronization |
|
|
232
|
+
| Reverse sync | Four canonical states above | Tracker comment mirroring, full bidirectional field sync |
|
|
233
|
+
| Parent epics | Consistent with #17 and #19 | Does not re-own the umbrella artifact model |
|
|
234
|
+
|
|
235
|
+
## 7. Related
|
|
236
|
+
|
|
237
|
+
- Parent workflow-family epic: [mfittko/pi-dev-loops#17](https://github.com/mfittko/pi-dev-loops/issues/17)
|
|
238
|
+
- Umbrella artifact model epic: [mfittko/pi-dev-loops#19](https://github.com/mfittko/pi-dev-loops/issues/19)
|
|
239
|
+
- This contract (first implementable slice): [mfittko/pi-dev-loops#21](https://github.com/mfittko/pi-dev-loops/issues/21)
|
|
240
|
+
- Copilot loop state graph: [Copilot Loop State Graph](../../docs/copilot-loop-state-graph.md)
|
|
241
|
+
- Reviewer loop state graph: [Reviewer Loop State Graph](../../docs/reviewer-loop-state-graph.md)
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## State machine integration
|
|
246
|
+
|
|
247
|
+
This document is also the canonical state-graph doc for the tracker-first loop state machine.
|
|
248
|
+
|
|
249
|
+
### Loop state machine (distinct from PR-level machine above)
|
|
250
|
+
|
|
251
|
+
Implementation:
|
|
252
|
+
- `packages/core/src/loop/tracker-first-loop-state.mjs` — pure logic layer (`interpretTrackerLoopState`)
|
|
253
|
+
- `scripts/loop/detect-tracker-first-loop-state.mjs` — CLI wrapper (same interface as `detect-copilot-loop-state.mjs`)
|
|
254
|
+
|
|
255
|
+
**Loop state vocabulary:** `drafting`, `needs_triage`, `in_progress`, `in_review`, `merge_ready`, `blocked`, `completed`, `unknown`
|
|
256
|
+
|
|
257
|
+
**Loop interface contract:** `{ ok, state, snapshot, allowedTransitions, nextAction }`
|
|
258
|
+
|
|
259
|
+
**Loop snapshot fields:**
|
|
260
|
+
| Field | Type | Description |
|
|
261
|
+
|---|---|---|
|
|
262
|
+
| `trackerState` | `string` | Canonical loop state |
|
|
263
|
+
| `rawTrackerState` | `string` | Raw input state string |
|
|
264
|
+
| `prLinked` | `boolean` | Whether a linked PR was found |
|
|
265
|
+
| `prContext` | `object \| null` | Linked PR context (number, state, headRefName) |
|
|
266
|
+
|
|
267
|
+
**Loop nextAction mapping:**
|
|
268
|
+
| State | nextAction |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `drafting` | `triage_or_block` |
|
|
271
|
+
| `needs_triage` | `start_work` |
|
|
272
|
+
| `in_progress` | `review` |
|
|
273
|
+
| `in_review` | `merge_or_fix` |
|
|
274
|
+
| `merge_ready` | `merge` |
|
|
275
|
+
| `blocked` | `resolve_blocker` |
|
|
276
|
+
| `completed` | `done` |
|
|
277
|
+
| `unknown` | `reconcile` |
|
|
278
|
+
|
|
279
|
+
**Fail-closed contract:** Unrecognized/empty/garbage tracker state → `needs_triage`. Only explicit `"unknown"` → canonical `unknown` state.
|
|
280
|
+
|
|
281
|
+
**PR-level state machine** (sections 1-5 above) uses a separate vocabulary (`ready_no_pr`, `draft_pr_open`, `pr_reviewable`, `pr_merged`, `pr_closed_unmerged`, `no_tracker_item`, `blocked_needs_user_decision`) with its own snapshot schema and reverse-sync actions.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Validation policy
|
|
2
|
+
|
|
3
|
+
Canonical owner for validation requirements across all workflow families.
|
|
4
|
+
|
|
5
|
+
## Default validation
|
|
6
|
+
|
|
7
|
+
- `npm run verify` is the default repo-level local validation path
|
|
8
|
+
- Must pass before: PR creation, gate entry, merge
|
|
9
|
+
- At minimum: `npm test && npm run test:dev-loop`
|
|
10
|
+
|
|
11
|
+
## Gate-specific requirements
|
|
12
|
+
|
|
13
|
+
| Gate | Validation required |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `draft_gate` | CI green on current head (or `--local-validation-head-sha` if CI absent) |
|
|
16
|
+
| `pre_approval_gate` | CI green on current head + resolved review threads + clean re-review |
|
|
17
|
+
|
|
18
|
+
## Coverage requirements
|
|
19
|
+
|
|
20
|
+
- ≥90% coverage for lines, statements, functions, and branches on changed files
|
|
21
|
+
- Test-first for all non-trivial logic
|
|
22
|
+
|
|
23
|
+
## Cross-references
|
|
24
|
+
|
|
25
|
+
- [Merge preconditions](merge-preconditions.md)
|
|
26
|
+
- [Stop conditions](stop-conditions.md)
|
|
27
|
+
- [Public Dev Loop Contract](public-dev-loop-contract.md)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Workflow Handoff — Derivation Contract
|
|
2
|
+
|
|
3
|
+
> **Status:** This document defines the **contract** for the
|
|
4
|
+
> `buildDevLoopHandoffEnvelope()` function in `@dev-loops/core`.
|
|
5
|
+
> Agents should read the envelope as their first artifact and then load
|
|
6
|
+
> only the listed `requiredReads` before executing `nextAction`.
|
|
7
|
+
|
|
8
|
+
## Authoritative sources
|
|
9
|
+
|
|
10
|
+
Every field in the handoff envelope is derived from authoritative sources as shown below. No field uses a hard-coded magic string or prose
|
|
11
|
+
template.
|
|
12
|
+
|
|
13
|
+
| Source | Fields derived |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Resolver output (`resolve-dev-loop-startup.mjs` bundle) | `target`, `nextAction`, `requiredReads`, `executionMode` |
|
|
16
|
+
| Caller options (`repoRoot`, `worktreeCwd`) | `cwd` |
|
|
17
|
+
| Gate state (detectors) + strategy defaults | `currentGate`, `worktreeRequired` |
|
|
18
|
+
| Settings (`.devloops` at repo root + `defaults.yaml`) | `gateConfig`, `stopRules`, `asyncStartMode`, `requireDraftFirst`, `maxCopilotRounds` |
|
|
19
|
+
| Gate state (detectors) | `currentHeadSha`, `ciStatus`, `unresolvedThreadCount`, `copilotRoundCount` |
|
|
20
|
+
|
|
21
|
+
## Acceptance templates
|
|
22
|
+
|
|
23
|
+
`acceptance.criteria`, `acceptance.evidence`, `acceptance.maxFinalizationTurns`,
|
|
24
|
+
and `control.*` are derived from a static strategy+gate mapping table:
|
|
25
|
+
|
|
26
|
+
| Strategy | Gate | criteria | evidence | maxFinalizationTurns | needsAttentionAfterMs |
|
|
27
|
+
|---|---|---|---|---|---|
|
|
28
|
+
| `copilot_pr_followup` | `draft` | AC check, scope, coverage, DoD alignment | commands-run, validation-output, review-findings | 4 | 300000 |
|
|
29
|
+
| `copilot_pr_followup` | `watch` | Copilot activity detection, no stuck watch | commands-run | 2 | 1800000 |
|
|
30
|
+
| `copilot_pr_followup` | `pre-approval` | Full pre-approval gate chain, clean verdict, unresolved threads, CI green | commands-run, validation-output, review-findings, residual-risks | 6 | 300000 |
|
|
31
|
+
| `final_approval` | `default` | Gate evidence, human confirmation, CI green | validation-output, manual-notes | 2 | 300000 |
|
|
32
|
+
| `local_implementation` | `default` | Phase-acceptance criteria, verify green | commands-run, validation-output, changed-files | 6 | 300000 |
|
|
33
|
+
| `issue_intake` | `default` | Contract compliance | commands-run, validation-output | 4 | 300000 |
|
|
34
|
+
| `external_pr_followup` | `default` | Contract compliance | commands-run, validation-output | 4 | 300000 |
|
|
35
|
+
| `reviewer_fixer` | `default` | Contract compliance | commands-run, validation-output | 4 | 300000 |
|
|
36
|
+
| `wait_watch` | `default` | Contract compliance | commands-run, validation-output | 4 | 1800000 |
|
|
37
|
+
|
|
38
|
+
Unknown strategy+gate combinations throw an explicit error listing known combos.
|
|
39
|
+
|
|
40
|
+
## Stop rules
|
|
41
|
+
|
|
42
|
+
Stop rules are derived from `settings.autonomy.stopAt` when present.
|
|
43
|
+
When absent, strategy defaults apply:
|
|
44
|
+
|
|
45
|
+
| Strategy | Default stop rules |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `copilot_pr_followup` | `["draft-pr", "merge"]` |
|
|
48
|
+
| `issue_intake` | `["merge"]` |
|
|
49
|
+
| `external_pr_followup` | `["merge"]` |
|
|
50
|
+
| `reviewer_fixer` | `["merge"]` |
|
|
51
|
+
| `wait_watch` | `["merge"]` |
|
|
52
|
+
| `final_approval` | `["merge"]` |
|
|
53
|
+
| `local_implementation` | `[]` (auto-continue) |
|
|
54
|
+
|
|
55
|
+
## Envelope schema
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface HandoffEnvelope {
|
|
59
|
+
handoffVersion: 1;
|
|
60
|
+
derivedAt: string; // ISO timestamp
|
|
61
|
+
|
|
62
|
+
target: {
|
|
63
|
+
kind: "issue" | "pr" | "local_branch" | "local_phase";
|
|
64
|
+
repo: string;
|
|
65
|
+
issue?: number;
|
|
66
|
+
pr?: number;
|
|
67
|
+
linkedPr?: number;
|
|
68
|
+
branch?: string;
|
|
69
|
+
phase?: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
currentGate: string;
|
|
73
|
+
currentHeadSha: string | null;
|
|
74
|
+
ciStatus: string | null;
|
|
75
|
+
unresolvedThreadCount: number;
|
|
76
|
+
copilotRoundCount: number;
|
|
77
|
+
maxCopilotRounds: number;
|
|
78
|
+
executionMode: "bounded_handoff" | "durable_auto";
|
|
79
|
+
|
|
80
|
+
nextAction: string;
|
|
81
|
+
requiredReads: string[];
|
|
82
|
+
|
|
83
|
+
gateConfig?: {
|
|
84
|
+
angles: string[];
|
|
85
|
+
excludeAngles?: string[];
|
|
86
|
+
blockCleanOnFindingSeverities: string[];
|
|
87
|
+
requireCi: boolean;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
stopRules: string[];
|
|
91
|
+
asyncStartMode: "required" | "allowed";
|
|
92
|
+
requireDraftFirst: boolean;
|
|
93
|
+
|
|
94
|
+
cwd: string | null;
|
|
95
|
+
worktreeRequired: boolean;
|
|
96
|
+
|
|
97
|
+
acceptance: {
|
|
98
|
+
criteria: Array<{ id: string; must: string; severity: "required" | "recommended" }>;
|
|
99
|
+
evidence: string[];
|
|
100
|
+
maxFinalizationTurns: number;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
control: {
|
|
104
|
+
needsAttentionAfterMs: number;
|
|
105
|
+
activeNoticeAfterMs: number;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
overrides?: {
|
|
109
|
+
mergeAuthorized?: boolean;
|
|
110
|
+
preferLocal?: boolean;
|
|
111
|
+
scopeConstraint?: string;
|
|
112
|
+
customStopAt?: string;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Agent consumption pattern
|
|
118
|
+
|
|
119
|
+
1. Read the handoff envelope as the first artifact.
|
|
120
|
+
2. Read every path listed in `requiredReads` (in order).
|
|
121
|
+
3. Execute `nextAction`.
|
|
122
|
+
4. Respect `stopRules` — do not proceed past a gated stop point without authorization.
|
|
123
|
+
5. Use `acceptance` to self-validate before declaring completion.
|
|
124
|
+
|
|
125
|
+
## Backward compatibility
|
|
126
|
+
|
|
127
|
+
The `acceptance` block maps 1:1 into the existing `subagent()` acceptance
|
|
128
|
+
contract shape. When the envelope is present, no separate prose task
|
|
129
|
+
parameter is required.
|
|
130
|
+
|
|
131
|
+
## Non-goals
|
|
132
|
+
|
|
133
|
+
- This contract does not define dispatch mechanics.
|
|
134
|
+
- This contract does not define UI/UX for envelope display.
|
|
135
|
+
- This contract does not modify the `subagent()` API itself.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: final-approval
|
|
3
|
+
description: >-
|
|
4
|
+
Internal routed strategy behind `dev-loop` for the final human approval and
|
|
5
|
+
merge gate. The canonical procedure now lives in copilot-pr-followup.
|
|
6
|
+
compatibility: Pi skill for git+GitHub repositories. Requires gh auth.
|
|
7
|
+
allowed-tools: read bash edit write subagent review_loop
|
|
8
|
+
user-invocable: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Final Approval (redirect)
|
|
12
|
+
|
|
13
|
+
This route now uses [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md) as the canonical procedure owner.
|
|
14
|
+
|
|
15
|
+
When the public router selects `final_approval`, load [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md)
|
|
16
|
+
and follow its **Human approval checkpoint** section inside Step 7.
|
|
17
|
+
|
|
18
|
+
Use this redirect only as a narrowed read-set pointer for the routed `final_approval` strategy.
|
|
19
|
+
Do not restate merge-ready preconditions, gate evidence rules, or merge authorization policy here.
|