create-agentic-pdlc 1.2.1 → 2.0.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/SETUP.md CHANGED
@@ -41,7 +41,7 @@ Note down the `PROJECT_ID` and the `STATUS_FIELD_ID` for future steps.
41
41
  ```bash
42
42
  REPO="owner/repo"
43
43
  gh label create "spec:approved" --repo $REPO --color "0e8a16" --description "Spec approved — agent can implement"
44
- gh label create "pr:review" --repo $REPO --color "e4e669" --description "PR awaiting code review"
44
+ gh label create "pr:in-review" --repo $REPO --color "e4e669" --description "PR awaiting code review"
45
45
  gh label create "pr:approved" --repo $REPO --color "0e8a16" --description "PR approved, ready for merge"
46
46
  gh label create "architecture-violation" --repo $REPO --color "d93f0b" --description "Invariant violation detected by CI"
47
47
  ```
@@ -122,13 +122,52 @@ For each known idea or feature, create an issue using the convention:
122
122
  gh issue create \
123
123
  --repo owner/repo \
124
124
  --title "👤 US: [short description]" \
125
- --body "Initial idea issue. Spec to be detailed."
125
+ --body "**As** [user],
126
+ **I want** [action],
127
+ **so that** [benefit].
128
+
129
+ ---
130
+
131
+ Initial idea issue. Spec to be detailed."
126
132
  ```
127
133
 
128
134
  Move the issues to the `Idea` column on the board matching your setup.
129
135
 
130
136
  ---
131
137
 
138
+ ## (Optional) Architecture Violation Integration
139
+
140
+ If your project uses an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label), the Setup Mode can automatically add a GitHub Actions job to `project-automation.yml` that moves these issues to the `Idea` column.
141
+
142
+ If you skipped this during setup but want to add it later, you can append the following job to `.github/workflows/project-automation.yml` under the `jobs` section:
143
+
144
+ ```yaml
145
+ move-violation-to-board:
146
+ name: architecture-violation → 💡 Idea
147
+ if: github.event_name == 'issues' && github.event.label.name == 'architecture-violation'
148
+ runs-on: ubuntu-latest
149
+ steps:
150
+ - uses: actions/github-script@v7
151
+ with:
152
+ github-token: ${{ secrets.PROJECT_TOKEN }}
153
+ script: |
154
+ const issueNodeId = context.payload.issue.node_id;
155
+ const addResult = await github.graphql(`
156
+ mutation($p: ID!, $c: ID!) {
157
+ addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
158
+ }`, { p: process.env.PROJECT_ID, c: issueNodeId });
159
+ const itemId = addResult.addProjectV2ItemById.item.id;
160
+ await github.graphql(`
161
+ mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
162
+ updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
163
+ projectV2Item { id }
164
+ }
165
+ }`, { p: process.env.PROJECT_ID, i: itemId, f: process.env.STATUS_FIELD_ID,
166
+ v: { singleSelectOptionId: process.env.STATUS_IDEA } });
167
+ ```
168
+
169
+ ---
170
+
132
171
  ## Final Verification Checklist
133
172
 
134
173
  - [ ] Board has 10 columns fully configured
@@ -13,19 +13,22 @@ If the user invokes you in a new project, you must first check if the PDLC artif
13
13
  Specifically, check for:
14
14
  - `AGENTS.md`
15
15
  - `docs/pdlc.md`
16
+ - `.github/CODEOWNERS`
16
17
  - `.github/workflows/project-automation.yml`
17
18
  - `.github/workflows/agent-trigger.yml`
19
+ - `.github/workflows/pdlc-health-check.yml`
18
20
 
19
21
  If any of these files are missing, you are in **Setup Mode**. Do not proceed with feature requests until setup is complete.
20
22
  1. Acknowledge that the framework is not yet set up.
21
23
  2. Interactively ask the user for required values **one group at a time**:
22
- - **Project basics:** Project Name, Description, Technical Stack (Structure).
24
+ - **Project basics:** Project Name, Description, Technical Stack (Structure), and GitHub Username (for CODEOWNERS security).
23
25
  - **Commands:** Test command, Lint command, Build command.
24
26
  - **Invariants:** Critical business rules agents must never violate (e.g. Human-in-the-loop).
25
27
  - **Board IDs:** PROJECT_ID, STATUS_FIELD_ID, column option IDs (provide standard PDLC options: Idea, Exploration, Brainstorming, Detail Solution, Approval, Development, Testing, Code Review / PR, Merge, Production). Allow user to answer "skip", which means you leave the placeholders intact.
28
+ - **Architecture Violation:** Ask "Does your project use an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label)?". If yes, replace `{{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}` in `project-automation.yml` with the job definition (available in the framework documentation). If no, ask if they would like help implementing one, reminding them that it significantly improves their agentic development process. If they decline, remove the placeholder.
26
29
  - **Implementation agent handle:** e.g., `@google-labs-jules`, or "none".
27
30
  3. Generate and write the missing files replacing the `{{SCREAMING_SNAKE_CASE}}` placeholders using the templates logic you know (usually they reside in standard Agentic PDLC templates).
28
- 4. Offer to run the `gh` commands for labels (`spec:approved`, `pr:review`, `pr:approved`, `architecture-violation`).
31
+ 4. Offer to run the `gh` commands for labels (`spec:approved`, `pr:in-review`, `pr:approved`, `architecture-violation`).
29
32
  5. Commit everything with the message: `chore: setup agentic-pdlc framework`.
30
33
  6. Conclude Setup Mode.
31
34
 
@@ -44,6 +47,18 @@ When asked to work on a feature, you will:
44
47
 
45
48
  ### 2. Creating the Spec
46
49
  Once approved, you will detail the solution directly into the GitHub Issue body. Focus on precise Acceptance Criteria.
50
+ **IMPORTANT:** You must always rewrite the full issue body to include both the user story and the Acceptance Criteria. Do not simply append the ACs to the existing text. Use this format:
51
+
52
+ ```
53
+ **As** [user],
54
+ **I want** [action],
55
+ **so that** [benefit].
56
+
57
+ ---
58
+
59
+ ## Acceptance Criteria
60
+ ...
61
+ ```
47
62
 
48
63
  ### 3. Handoff
49
64
  Do not write code for downstream features! Your goal is to refine the Spec, so the human Tech Lead can label the issue `spec:approved`. This label triggers the downstream agent via `agent-trigger.yml`.
package/docs/flow.md ADDED
@@ -0,0 +1,160 @@
1
+ # PDLC Flow: From Idea to Production
2
+
3
+ This document describes the full lifecycle of a card on the agentic-pdlc board — who acts at each stage, what triggers each transition, which labels are added or removed, and where human gates are required.
4
+
5
+ ---
6
+
7
+ ## Roles
8
+
9
+ | Role | Responsibility |
10
+ |------|---------------|
11
+ | **PM** (human) | Selects issues for the sprint, approves brainstorm (Gate 1), approves spec (Gate 2) |
12
+ | **TL / Reviewer** (human) | Co-approves spec for technical decisions (Gate 2), reviews and approves the PR (Gate 3) |
13
+ | **Claude** | Exploration, brainstorming, spec writing — acts on PM instruction via chat or via upstream label |
14
+ | **Implementation Agent** | Implementation, running tests, opening the PR |
15
+ | **Workflow** | All label swaps and card movements — the source of truth for board state |
16
+
17
+ > **Principle:** Every board transition must be triggered by a GitHub event (label, PR, review) processed by a workflow. Agents must never be responsible for moving cards.
18
+
19
+ ---
20
+
21
+ ## Step-by-Step Flow
22
+
23
+ ### 💡 Idea
24
+ Issue exists in the backlog with no `upstream:` label.
25
+
26
+ ---
27
+
28
+ ### 🔍 Exploration
29
+
30
+ **Trigger (two equivalent paths):**
31
+ - PM tells Claude directly in chat → Claude adds `upstream:exploration` to the issue, OR
32
+ - PM adds `upstream:exploration` directly to the issue
33
+
34
+ **Workflow:** `project-automation.yml` detects `upstream:exploration` → moves card to Exploration.
35
+
36
+ **Who works:** Claude reads relevant code and context.
37
+
38
+ ---
39
+
40
+ ### 🧠 Brainstorming
41
+
42
+ **Trigger:** Claude, after exploration.
43
+
44
+ **Actions:**
45
+ - Claude posts a comment on the issue with findings and 2–3 proposed approaches
46
+ - Claude swaps `upstream:exploration` → `upstream:brainstorming`
47
+
48
+ **Workflow:** `project-automation.yml` moves card to Brainstorming.
49
+
50
+ **⏸ Human gate (Gate 1 — PM):** PM reads the brainstorming comment and selects an approach. This can be done:
51
+ - By commenting on the issue (e.g., "Option A", "Go with B", "approved", "lgtm")
52
+ - By telling Claude in chat
53
+
54
+ **Note on implicit approval:** If Claude presented multiple options, selecting one (e.g., "Option A") counts as implicit approval. The `upstream-gate.yml` detects option-selection patterns in addition to explicit approval words.
55
+
56
+ ---
57
+
58
+ ### 📐 Detail Solution ← Gate 1
59
+
60
+ **Trigger:** `upstream-gate.yml` detects PM approval comment on a `upstream:brainstorming` issue → swaps `upstream:brainstorming` → `upstream:detailing` via `PROJECT_TOKEN`.
61
+
62
+ **Who works:** Claude rewrites the issue body with:
63
+ 1. User story (`As… I want… So that…`)
64
+ 2. Acceptance Criteria (AC1, AC2, …)
65
+ 3. Files to modify
66
+
67
+ **After spec is written:** Claude swaps `upstream:detailing` → `upstream:approval`.
68
+
69
+ **Workflow:** `project-automation.yml` moves card to Approval.
70
+
71
+ ---
72
+
73
+ ### ✅ Approval
74
+
75
+ **⏸ Human gate (Gate 2 — PM + TL):** Both PM (business decisions) and TL (technical decisions) review the spec. When both are satisfied, PM adds label `spec:approved`.
76
+
77
+ **Workflow:** `agent-trigger.yml` detects `spec:approved` →
78
+ 1. Removes `upstream:approval`
79
+ 2. Adds `upstream:development`
80
+ 3. Adds specific agent label (e.g., `jules`)
81
+ 4. Posts a structured comment with implementation instructions for the Agent
82
+
83
+ **Workflow:** `project-automation.yml` moves card to Development.
84
+
85
+ ---
86
+
87
+ ### ⚙️ Development
88
+
89
+ **Who works:** Implementation Agent implements the spec strictly within the Acceptance Criteria.
90
+
91
+ **When done:** Agent adds `upstream:testing` before running tests.
92
+
93
+ **Workflow:** `project-automation.yml` moves card to Testing.
94
+
95
+ ---
96
+
97
+ ### 🧪 Testing
98
+
99
+ **Who works:** Agent runs the test suite (`vitest run` + `typecheck`).
100
+
101
+ **When tests pass:** Agent opens a PR with `Closes #N` in the body.
102
+
103
+ **Workflow:** `project-automation.yml` detects PR opened → moves linked issue to Code Review, adds `pr:in-review` label to the PR.
104
+
105
+ ---
106
+
107
+ ### 👁 Code Review ← Gate 3
108
+
109
+ **⏸ Human gate (Gate 3 — TL / PM):** Reviewer reads the PR, verifies ACs, checks for regressions.
110
+
111
+ **Trigger:** Reviewer approves the PR via GitHub's native review interface (no label needed).
112
+
113
+ **Workflow:** `project-automation.yml` detects `pull_request_review: approved` → moves card to Production upon merge. Adds `pr:approved` label to the PR.
114
+
115
+ ---
116
+
117
+ ### 🚀 Production
118
+
119
+ **Who acts:** PM or TL merges the PR.
120
+
121
+ **Workflow:** `project-automation.yml` detects PR merged → moves card to Production.
122
+
123
+ > **Note:** There is no separate "Merge" column. Review and merge happen in tight sequence in practice, and a transient column adds no visibility value.
124
+
125
+ ---
126
+
127
+ ## Label Reference
128
+
129
+ | Label | Added by | Removed by |
130
+ |-------|----------|------------|
131
+ | `upstream:exploration` | PM (human) or Claude | Claude |
132
+ | `upstream:brainstorming` | Claude | `upstream-gate.yml` |
133
+ | `upstream:detailing` | `upstream-gate.yml` | Claude |
134
+ | `upstream:approval` | Claude | `agent-trigger.yml` |
135
+ | `upstream:development` | `agent-trigger.yml` | Impl. Agent |
136
+ | `upstream:testing` | Impl. Agent | `project-automation.yml` (on PR open) |
137
+ | `spec:approved` | PM (human) | — |
138
+ | `agent_label` (e.g. `jules`, `sweep`) | `agent-trigger.yml` | — |
139
+ | `pr:in-review` | `project-automation.yml` | `project-automation.yml` |
140
+ | `pr:approved` | `project-automation.yml` | — |
141
+
142
+ ---
143
+
144
+ ## Human Gates Summary
145
+
146
+ | Gate | Who | Trigger | What they decide |
147
+ |------|-----|---------|-----------------|
148
+ | **Gate 1** | PM | Comment on brainstorming issue | Which approach to pursue |
149
+ | **Gate 2** | PM + TL | Add `spec:approved` label | Whether the spec is correct and complete |
150
+ | **Gate 3** | TL / PM | GitHub PR review approval | Whether the implementation meets the ACs |
151
+
152
+ ---
153
+
154
+ ## Known Risk: Autonomous Agents and Informal Comments
155
+
156
+ Implementation agents often monitor issue comments and can act on informal instructions (e.g., "@agent fix this") — bypassing Gates 1 and 2. This behavior is controlled by the agent's platform and cannot be prevented via GitHub Actions.
157
+
158
+ **Mitigation:** The effective code quality gate is Gate 3 (PR review + mandatory CI). Never comment directly on issues to instruct the agent outside the `spec:approved` flow.
159
+
160
+ See [issue #11](https://github.com/rafaeltcosta86/agentic-pdlc/issues/11) for full context.
package/docs/pdlc.md CHANGED
@@ -72,7 +72,7 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
72
72
  | `stage:detailing` | Issue | Blue | Technical spec is being written |
73
73
  | `stage:development` | Issue | Orange | Agent is implementing the spec |
74
74
  | `spec:approved` | Issue | Green | Gate 2 — agent is cleared to implement |
75
- | `pr:review` | PR | Yellow | Awaiting code review |
75
+ | `pr:in-review` | PR | Yellow | Awaiting code review |
76
76
  | `pr:approved` | PR | Green | Code review approved |
77
77
 
78
78
  ## Approval Gates
@@ -0,0 +1,39 @@
1
+ # Spike: Upstream Flow Gap Analysis
2
+
3
+ This document analyzes the three gaps identified in the upstream flow of the Agentic PDLC framework and proposes solutions to ensure future projects receive these behaviors out of the box.
4
+
5
+ ## 1. Sprint start → cards move to Exploration automatically
6
+
7
+ **Analysis:**
8
+ Currently, when a PM selects issues for a sprint and tells the upstream agent to begin, the cards do not move automatically unless the agent explicitly runs a `gh issue edit` command.
9
+ - `AGENTS.md` does not instruct the upstream agent to add `stage:exploration` (or equivalent) as its first action upon starting.
10
+ - `project-automation.yml` does respond to the label `stage:exploration` and moves the card to the Exploration column.
11
+ - The label naming convention (`stage:exploration`, `stage:brainstorming`, `stage:detailing`) is established in the workflow but not explicitly documented as a mandatory first step for the agent.
12
+
13
+ **Solution (Gap):**
14
+ - **Fix:** Update `AGENTS.md` and `adapters/claude-code/skill.md` to explicitly instruct the agent: *"When beginning work on a new issue, your first action must be to apply the `stage:exploration` label using the GitHub CLI."*
15
+
16
+ ## 2. Brainstorm gate — agent observes comments for PM approval
17
+
18
+ **Analysis:**
19
+ After the agent posts an exploration/brainstorming comment on the issue, it needs PM feedback (approval or requested changes) to proceed to Solution Detail.
20
+ - There is no mechanism (webhook or workflow) for the upstream agent to automatically detect PM approval in an issue comment.
21
+ - In current practice, the PM must manually notify the agent in the chat (e.g., "The brainstorm for #123 is approved").
22
+ - This is a known limitation of current agent interfaces (which require explicit chat prompts to resume execution) and is not documented in the framework.
23
+
24
+ **Solution (Gap):**
25
+ - **Fix:** Acknowledge this limitation in the framework documentation. Update `SETUP.md` and/or a new `docs/workflow-guide.md` to establish the pattern: *"To pass Gate 1 (Brainstorming), the PM must review the issue comments and explicitly tell the agent in the chat to proceed to detailing for that specific issue."*
26
+
27
+ ## 3. spec:approved → implementation agent picks up the card
28
+
29
+ **Analysis:**
30
+ Cards in the "Approval" column wait for the PM to add the `spec:approved` label to signal the handoff to the implementation agent.
31
+ - `agent-trigger.yml` correctly fires on the `spec:approved` label and comments on the issue to notify the implementation agent (e.g., Jules).
32
+ - However, when `spec:approved` is added, `project-automation.yml` currently tries to move the card to `STATUS_APPROVAL` — which is the column it is already in.
33
+ - The intent is for the card to move to "Development" when the handoff occurs.
34
+
35
+ **Solution (Gap):**
36
+ - **Fix:** Update `project-automation.yml`. In the `move-card-on-label` job, change the target status for `spec:approved` from `STATUS_APPROVAL` to `STATUS_DEVELOPMENT`.
37
+
38
+ ---
39
+ *This analysis addresses the questions raised in Issue #4.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agentic-pdlc",
3
- "version": "1.2.1",
3
+ "version": "2.0.0",
4
4
  "description": "Scaffold the Agentic PDLC framework effortlessly",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -0,0 +1,5 @@
1
+ # This file prevents autonomous agents from modifying core security, automation, and instruction rules
2
+ # without explicit approval from the repository owner.
3
+
4
+ .github/ @{{GITHUB_USERNAME}}
5
+ AGENTS.md @{{GITHUB_USERNAME}}
@@ -12,8 +12,41 @@ jobs:
12
12
  # Runs only when spec:approved is added
13
13
  if: github.event.label.name == 'spec:approved'
14
14
  runs-on: ubuntu-latest
15
+ permissions:
16
+ issues: write
17
+ pull-requests: write
18
+ contents: read
19
+ env:
20
+ PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
15
21
  steps:
16
- - name: Comment on issue to trigger agent
22
+ - name: Update Labels
23
+ if: ${{ env.PROJECT_TOKEN != '' }}
24
+ uses: actions/github-script@v7
25
+ with:
26
+ github-token: ${{ env.PROJECT_TOKEN }}
27
+ script: |
28
+ const { owner, repo } = context.repo;
29
+ const issue_number = context.payload.issue.number;
30
+
31
+ try {
32
+ await github.rest.issues.removeLabel({
33
+ owner,
34
+ repo,
35
+ issue_number,
36
+ name: 'upstream:approval'
37
+ });
38
+ } catch (error) {
39
+ console.log('Label upstream:approval not found or could not be removed');
40
+ }
41
+
42
+ await github.rest.issues.addLabels({
43
+ owner,
44
+ repo,
45
+ issue_number,
46
+ labels: ['upstream:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
47
+ });
48
+
49
+ - name: Comment on issue to trigger agent and prevent race conditions
17
50
  uses: actions/github-script@v7
18
51
  with:
19
52
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -22,6 +55,8 @@ jobs:
22
55
  const issueTitle = context.payload.issue.title;
23
56
 
24
57
  const body = [
58
+ `🤖 **Agentic PDLC Orchestrator:** I have dispatched the implementation agent. Please wait for the Pull Request and avoid making concurrent commits on this task to prevent race conditions.`,
59
+ '',
25
60
  `{{AGENT_HANDLE}} The spec for this issue has been approved. Please implement it exactly as described in the body above.`,
26
61
  '',
27
62
  '**Mandatory steps before you begin:**',
@@ -48,6 +83,10 @@ jobs:
48
83
  # Runs when architecture-violation is added (Sentinel flow)
49
84
  if: github.event.label.name == 'architecture-violation'
50
85
  runs-on: ubuntu-latest
86
+ permissions:
87
+ issues: write
88
+ pull-requests: write
89
+ contents: read
51
90
  steps:
52
91
  - name: Comment on issue to trigger agent
53
92
  uses: actions/github-script@v7
@@ -22,6 +22,9 @@ jobs:
22
22
  - name: Run Linters
23
23
  run: {{LINT_COMMAND}}
24
24
 
25
+ - name: Typecheck
26
+ run: {{TYPECHECK_COMMAND}}
27
+
25
28
  - name: Build
26
29
  run: {{BUILD_COMMAND}}
27
30
 
@@ -0,0 +1,123 @@
1
+ name: PDLC Health Check (Drift Detection)
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ schedule:
6
+ - cron: '0 8 * * 1' # Every Monday at 8am
7
+
8
+ env:
9
+ PROJECT_ID: "{{PROJECT_ID}}"
10
+ STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
11
+ STATUS_EXPLORATION: "{{ID_EXPLORATION}}"
12
+ STATUS_BRAINSTORMING: "{{ID_BRAINSTORMING}}"
13
+ STATUS_DETAILING: "{{ID_DETAILING}}"
14
+ STATUS_APPROVAL: "{{ID_APPROVAL}}"
15
+ STATUS_DEVELOPMENT: "{{ID_DEVELOPMENT}}"
16
+ STATUS_TESTING: "{{ID_TESTING}}"
17
+ STATUS_CODE_REVIEW_PR: "{{ID_CODE_REVIEW_PR}}"
18
+ STATUS_PRODUCTION: "{{ID_PRODUCTION}}"
19
+
20
+ jobs:
21
+ check-drift:
22
+ name: Detect Project Board Drift
23
+ runs-on: ubuntu-latest
24
+ env:
25
+ PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
26
+ permissions:
27
+ issues: write
28
+ steps:
29
+ - name: Validate Board Configuration
30
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
31
+ uses: actions/github-script@v7
32
+ with:
33
+ github-token: ${{ env.PROJECT_TOKEN }}
34
+ script: |
35
+ const projectId = process.env.PROJECT_ID;
36
+ const statusFieldId = process.env.STATUS_FIELD_ID;
37
+ const envVars = {
38
+ 'STATUS_EXPLORATION': process.env.STATUS_EXPLORATION,
39
+ 'STATUS_BRAINSTORMING': process.env.STATUS_BRAINSTORMING,
40
+ 'STATUS_DETAILING': process.env.STATUS_DETAILING,
41
+ 'STATUS_APPROVAL': process.env.STATUS_APPROVAL,
42
+ 'STATUS_DEVELOPMENT': process.env.STATUS_DEVELOPMENT,
43
+ 'STATUS_TESTING': process.env.STATUS_TESTING,
44
+ 'STATUS_CODE_REVIEW_PR': process.env.STATUS_CODE_REVIEW_PR,
45
+ 'STATUS_PRODUCTION': process.env.STATUS_PRODUCTION
46
+ };
47
+
48
+ const query = `
49
+ query($projectId: ID!) {
50
+ node(id: $projectId) {
51
+ ... on ProjectV2 {
52
+ title
53
+ fields(first: 20) {
54
+ nodes {
55
+ ... on ProjectV2SingleSelectField {
56
+ id
57
+ name
58
+ options {
59
+ id
60
+ name
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ `;
69
+
70
+ let result;
71
+ try {
72
+ result = await github.graphql(query, { projectId });
73
+ } catch (error) {
74
+ console.log("❌ Error fetching project. Verify your PROJECT_ID.");
75
+ console.log(error);
76
+ return;
77
+ }
78
+
79
+ const project = result.node;
80
+ if (!project) {
81
+ console.log("❌ Project not found.");
82
+ return;
83
+ }
84
+
85
+ const statusField = project.fields.nodes.find(f => f.id === statusFieldId);
86
+ if (!statusField) {
87
+ console.log("❌ Status field not found.");
88
+ return;
89
+ }
90
+
91
+ const validOptions = statusField.options;
92
+ const validOptionIds = validOptions.map(o => o.id);
93
+
94
+ let hasDrift = false;
95
+ let missingVars = [];
96
+
97
+ for (const [varName, id] of Object.entries(envVars)) {
98
+ if (id && !id.startsWith('{{') && !validOptionIds.includes(id)) {
99
+ hasDrift = true;
100
+ missingVars.push(varName);
101
+ }
102
+ }
103
+
104
+ if (hasDrift) {
105
+ console.log("🚨 Drift detected! The following mapped columns no longer exist: " + missingVars.join(", "));
106
+
107
+ let table = "| Column Name | New ID |\n|---|---|\n";
108
+ validOptions.forEach(opt => {
109
+ table += `| ${opt.name} | \`${opt.id}\` |\n`;
110
+ });
111
+
112
+ const body = `🚨 **Agentic PDLC Drift Detected**\n\nThe following columns mapped in your \`.github/workflows/project-automation.yml\` no longer exist in your project board:\n\n**${missingVars.join(", ")}**\n\n### How to fix it:\nHere is the list of current columns in your board with their valid IDs. Please update the \`env\` block in your \`.github/workflows/project-automation.yml\` and \`.github/workflows/pdlc-health-check.yml\`.\n\n${table}`;
113
+
114
+ await github.rest.issues.create({
115
+ owner: context.repo.owner,
116
+ repo: context.repo.repo,
117
+ title: '🚨 Agentic PDLC Drift Detected in Project Board',
118
+ body: body,
119
+ labels: ['bug']
120
+ });
121
+ } else {
122
+ console.log("✅ No drift detected. Board configuration is healthy.");
123
+ }
@@ -16,9 +16,9 @@ env:
16
16
  STATUS_DETAILING: "{{ID_DETAILING}}"
17
17
  STATUS_APPROVAL: "{{ID_APPROVAL}}"
18
18
  STATUS_DEVELOPMENT: "{{ID_DEVELOPMENT}}"
19
+ STATUS_TESTING: "{{ID_TESTING}}"
19
20
  STATUS_CODE_REVIEW_PR: "{{ID_CODE_REVIEW_PR}}"
20
- STATUS_MERGE: "{{ID_MERGE}}"
21
- STATUS_PRODUCAO: "{{ID_PRODUCAO}}"
21
+ STATUS_PRODUCTION: "{{ID_PRODUCTION}}"
22
22
 
23
23
  jobs:
24
24
  # Issue Labeled → Move Upstream
@@ -39,21 +39,24 @@ jobs:
39
39
  let targetStatusId = null;
40
40
  let stageName = null;
41
41
 
42
- if (labelName === 'stage:exploration') {
42
+ if (labelName === 'upstream:exploration') {
43
43
  targetStatusId = process.env.STATUS_EXPLORATION;
44
44
  stageName = 'Exploration';
45
- } else if (labelName === 'stage:brainstorming') {
45
+ } else if (labelName === 'upstream:brainstorming') {
46
46
  targetStatusId = process.env.STATUS_BRAINSTORMING;
47
47
  stageName = 'Brainstorming';
48
- } else if (labelName === 'stage:detailing') {
48
+ } else if (labelName === 'upstream:detailing') {
49
49
  targetStatusId = process.env.STATUS_DETAILING;
50
50
  stageName = 'Detailing';
51
- } else if (labelName === 'spec:approved') {
51
+ } else if (labelName === 'upstream:approval') {
52
52
  targetStatusId = process.env.STATUS_APPROVAL;
53
53
  stageName = 'Approval';
54
- } else if (labelName === 'stage:development') {
54
+ } else if (labelName === 'upstream:development') {
55
55
  targetStatusId = process.env.STATUS_DEVELOPMENT;
56
56
  stageName = 'Development';
57
+ } else if (labelName === 'upstream:testing') {
58
+ targetStatusId = process.env.STATUS_TESTING;
59
+ stageName = 'Testing';
57
60
  }
58
61
 
59
62
  if (!targetStatusId) {
@@ -83,6 +86,7 @@ jobs:
83
86
  await moveItem(node_id, targetStatusId);
84
87
  console.log(`Issue #${number} moved to ${stageName}`);
85
88
 
89
+ {{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}
86
90
 
87
91
  # PR Opened → Move linked issue to Code Review / PR
88
92
  move-card-on-pr-open:
@@ -136,17 +140,17 @@ jobs:
136
140
  console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
137
141
  }
138
142
 
139
- await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:review'] }).catch(() => {});
143
+ await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:in-review'] }).catch(() => {});
140
144
 
141
- # Review Approved → Merge
145
+ # Review Approved → Add Label
142
146
  move-card-on-review-approved:
143
- name: Approved PR → Merge
147
+ name: Approved PR → Add Label
144
148
  if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
145
149
  runs-on: ubuntu-latest
146
150
  env:
147
151
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
148
152
  steps:
149
- - name: Move issue to Merge
153
+ - name: Swap PR labels
150
154
  if: ${{ env.PROJECT_TOKEN != '' }}
151
155
  uses: actions/github-script@v7
152
156
  with:
@@ -154,34 +158,7 @@ jobs:
154
158
  script: |
155
159
  const prNumber = context.payload.pull_request.number;
156
160
  const { owner, repo } = context.repo;
157
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
158
- const body = pr.body ?? '';
159
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)].map(m => parseInt(m[1]));
160
-
161
- const moveItem = async (nodeId) => {
162
- const { addProjectV2ItemById: { item } } = await github.graphql(`
163
- mutation($p: ID!, $c: ID!) {
164
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
165
- }`, { p: process.env.PROJECT_ID, c: nodeId });
166
- await github.graphql(`
167
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
168
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
169
- projectV2Item { id }
170
- }
171
- }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
172
- v: { singleSelectOptionId: process.env.STATUS_MERGE } });
173
- };
174
-
175
- if (linkedIssues.length > 0) {
176
- for (const n of linkedIssues) {
177
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
178
- await moveItem(issue.node_id);
179
- }
180
- } else {
181
- await moveItem(pr.node_id);
182
- }
183
-
184
- try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: 'pr:review' }); } catch {}
161
+ try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: 'pr:in-review' }); } catch {}
185
162
  await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:approved'] }).catch(() => {});
186
163
 
187
164
  # PR Merged → Production
@@ -215,7 +192,7 @@ jobs:
215
192
  projectV2Item { id }
216
193
  }
217
194
  }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
218
- v: { singleSelectOptionId: process.env.STATUS_PRODUCAO } });
195
+ v: { singleSelectOptionId: process.env.STATUS_PRODUCTION } });
219
196
  };
220
197
 
221
198
  if (linkedIssues.length > 0) {