openplanr 2.1.1 → 2.2.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/cli/commands/planning-artifacts.d.ts.map +1 -1
  3. package/dist/cli/commands/planning-artifacts.js +6 -18
  4. package/dist/cli/commands/planning-artifacts.js.map +1 -1
  5. package/dist/cli/commands/sprint-refinement.d.ts +5 -0
  6. package/dist/cli/commands/sprint-refinement.d.ts.map +1 -0
  7. package/dist/cli/commands/sprint-refinement.js +141 -0
  8. package/dist/cli/commands/sprint-refinement.js.map +1 -0
  9. package/dist/cli/commands/status.d.ts.map +1 -1
  10. package/dist/cli/commands/status.js +4 -2
  11. package/dist/cli/commands/status.js.map +1 -1
  12. package/dist/cli/commands/update.d.ts.map +1 -1
  13. package/dist/cli/commands/update.js +5 -8
  14. package/dist/cli/commands/update.js.map +1 -1
  15. package/dist/dashboard/.vite/manifest.json +1 -1
  16. package/dist/dashboard/assets/{index-BCvntXFj.js → index-B74ddyXA.js} +2 -2
  17. package/dist/dashboard/assets/{index-BCvntXFj.js.map → index-B74ddyXA.js.map} +1 -1
  18. package/dist/dashboard/dashboard-manifest.json +8 -8
  19. package/dist/dashboard/index.html +1 -1
  20. package/dist/models/sprint-refinement-schema.d.ts +122 -0
  21. package/dist/models/sprint-refinement-schema.d.ts.map +1 -0
  22. package/dist/models/sprint-refinement-schema.js +147 -0
  23. package/dist/models/sprint-refinement-schema.js.map +1 -0
  24. package/dist/models/types.d.ts +8 -0
  25. package/dist/models/types.d.ts.map +1 -1
  26. package/dist/services/delivery-status-service.d.ts +6 -1
  27. package/dist/services/delivery-status-service.d.ts.map +1 -1
  28. package/dist/services/delivery-status-service.js +28 -1
  29. package/dist/services/delivery-status-service.js.map +1 -1
  30. package/dist/services/git-service.d.ts +19 -0
  31. package/dist/services/git-service.d.ts.map +1 -1
  32. package/dist/services/git-service.js +41 -0
  33. package/dist/services/git-service.js.map +1 -1
  34. package/dist/services/graph-service.d.ts.map +1 -1
  35. package/dist/services/graph-service.js +3 -1
  36. package/dist/services/graph-service.js.map +1 -1
  37. package/dist/services/sprint-refinement-service.d.ts +162 -0
  38. package/dist/services/sprint-refinement-service.d.ts.map +1 -0
  39. package/dist/services/sprint-refinement-service.js +645 -0
  40. package/dist/services/sprint-refinement-service.js.map +1 -0
  41. package/dist/templates/sprints/refinement.md.hbs +94 -0
  42. package/dist/templates/sprints/sprint-tasks.md.hbs +16 -0
  43. package/dist/templates/sprints/sprint.md.hbs +17 -12
  44. package/dist/utils/constants.d.ts +2 -0
  45. package/dist/utils/constants.d.ts.map +1 -1
  46. package/dist/utils/constants.js +6 -1
  47. package/dist/utils/constants.js.map +1 -1
  48. package/docs/CLI.md +26 -2
  49. package/lib/host-packages/adapter-registry.json +1 -1
  50. package/lib/host-packages/capability-map.json +16 -0
  51. package/lib/host-packages/claude/openplanr/.openplanr-content.json +27 -7
  52. package/lib/host-packages/claude/openplanr/skills/design/scripts/runtime/packages/protocol/package.json +1 -1
  53. package/lib/host-packages/claude/openplanr/skills/design-loop/scripts/runtime/packages/protocol/package.json +1 -1
  54. package/lib/host-packages/claude/openplanr/skills/design-review/scripts/runtime/packages/protocol/package.json +1 -1
  55. package/lib/host-packages/claude/openplanr/skills/openplanr/SKILL.md +1 -0
  56. package/lib/host-packages/claude/openplanr/skills/plan/scripts/runtime/packages/protocol/package.json +1 -1
  57. package/lib/host-packages/claude/openplanr/skills/sprint/SKILL.md +181 -0
  58. package/lib/host-packages/claude/openplanr/skills/sprint/openplanr.skill.json +59 -0
  59. package/lib/host-packages/claude/openplanr/skills/sprint/references/refinement-contract.md +154 -0
  60. package/lib/host-packages/claude/openplanr/skills/sprint/references/sprint-formats.md +146 -0
  61. package/lib/host-packages/claude/openplanr/skills/sprint/schemas/refinement.schema.json +140 -0
  62. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +24 -8
  63. package/lib/host-packages/cursor/openplanr/manifest.json +2 -1
  64. package/lib/host-packages/cursor/openplanr/rules/planr-design/scripts/runtime/packages/protocol/package.json +1 -1
  65. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/scripts/runtime/packages/protocol/package.json +1 -1
  66. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/scripts/runtime/packages/protocol/package.json +1 -1
  67. package/lib/host-packages/cursor/openplanr/rules/planr-openplanr.mdc +1 -0
  68. package/lib/host-packages/cursor/openplanr/rules/planr-plan/scripts/runtime/packages/protocol/package.json +1 -1
  69. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/refinement-contract.md +154 -0
  70. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/references/sprint-formats.md +146 -0
  71. package/lib/host-packages/cursor/openplanr/rules/planr-sprint/schemas/refinement.schema.json +140 -0
  72. package/lib/host-packages/cursor/openplanr/rules/planr-sprint.mdc +180 -0
  73. package/lib/host-packages/openai/openplanr/.openplanr-content.json +31 -7
  74. package/lib/host-packages/openai/openplanr/skills/design/scripts/runtime/packages/protocol/package.json +1 -1
  75. package/lib/host-packages/openai/openplanr/skills/design-loop/scripts/runtime/packages/protocol/package.json +1 -1
  76. package/lib/host-packages/openai/openplanr/skills/design-review/scripts/runtime/packages/protocol/package.json +1 -1
  77. package/lib/host-packages/openai/openplanr/skills/openplanr/SKILL.md +1 -0
  78. package/lib/host-packages/openai/openplanr/skills/plan/scripts/runtime/packages/protocol/package.json +1 -1
  79. package/lib/host-packages/openai/openplanr/skills/sprint/SKILL.md +181 -0
  80. package/lib/host-packages/openai/openplanr/skills/sprint/agents/openai.yaml +6 -0
  81. package/lib/host-packages/openai/openplanr/skills/sprint/openplanr.skill.json +59 -0
  82. package/lib/host-packages/openai/openplanr/skills/sprint/references/refinement-contract.md +154 -0
  83. package/lib/host-packages/openai/openplanr/skills/sprint/references/sprint-formats.md +146 -0
  84. package/lib/host-packages/openai/openplanr/skills/sprint/schemas/refinement.schema.json +140 -0
  85. package/package.json +2 -2
@@ -3,12 +3,12 @@
3
3
  "schemaVersion": "1.0.0",
4
4
  "protocolVersion": "1.8.0",
5
5
  "host": "cursor",
6
- "skillCount": 26,
6
+ "skillCount": 27,
7
7
  "roleCount": 0,
8
8
  "files": [
9
9
  {
10
10
  "path": "manifest.json",
11
- "digest": "sha256:c1c27693fe61e7cad7018a4f2ecb6e32f4fe5de078ee2ff6e6401a9b2a03422c"
11
+ "digest": "sha256:c01accc0506262e932ce531f0fdbec6f0fc9406c4e05d65d13e36dd8c8b1dfc5"
12
12
  },
13
13
  {
14
14
  "path": "rules/planr-artifact.mdc",
@@ -284,7 +284,7 @@
284
284
  },
285
285
  {
286
286
  "path": "rules/planr-design-loop/scripts/runtime/packages/protocol/package.json",
287
- "digest": "sha256:9a11f3b5e52bb2bd3f2310a9cbc1276b62b1b08e401279769228d5bfd8567995"
287
+ "digest": "sha256:d3a009b9b304680df08d3ec30bccea5b0baf7444fee4f65e90708125535d8773"
288
288
  },
289
289
  {
290
290
  "path": "rules/planr-design-loop/scripts/runtime/packages/protocol/registry/artifact-theme.json",
@@ -448,7 +448,7 @@
448
448
  },
449
449
  {
450
450
  "path": "rules/planr-design-review/scripts/runtime/packages/protocol/package.json",
451
- "digest": "sha256:9a11f3b5e52bb2bd3f2310a9cbc1276b62b1b08e401279769228d5bfd8567995"
451
+ "digest": "sha256:d3a009b9b304680df08d3ec30bccea5b0baf7444fee4f65e90708125535d8773"
452
452
  },
453
453
  {
454
454
  "path": "rules/planr-design-review/scripts/runtime/packages/protocol/registry/artifact-theme.json",
@@ -612,7 +612,7 @@
612
612
  },
613
613
  {
614
614
  "path": "rules/planr-design/scripts/runtime/packages/protocol/package.json",
615
- "digest": "sha256:9a11f3b5e52bb2bd3f2310a9cbc1276b62b1b08e401279769228d5bfd8567995"
615
+ "digest": "sha256:d3a009b9b304680df08d3ec30bccea5b0baf7444fee4f65e90708125535d8773"
616
616
  },
617
617
  {
618
618
  "path": "rules/planr-design/scripts/runtime/packages/protocol/registry/artifact-theme.json",
@@ -716,7 +716,7 @@
716
716
  },
717
717
  {
718
718
  "path": "rules/planr-openplanr.mdc",
719
- "digest": "sha256:bf88b2c937e39ab2436786abaeb2dfe58d90832f12afb496f1100845a94d8719"
719
+ "digest": "sha256:42a31d5d6a2e8b13068b10cfcee3e7ca00d4fc421933d1dedb8f5a83a84954a8"
720
720
  },
721
721
  {
722
722
  "path": "rules/planr-operate.mdc",
@@ -808,7 +808,7 @@
808
808
  },
809
809
  {
810
810
  "path": "rules/planr-plan/scripts/runtime/packages/protocol/package.json",
811
- "digest": "sha256:9a11f3b5e52bb2bd3f2310a9cbc1276b62b1b08e401279769228d5bfd8567995"
811
+ "digest": "sha256:d3a009b9b304680df08d3ec30bccea5b0baf7444fee4f65e90708125535d8773"
812
812
  },
813
813
  {
814
814
  "path": "rules/planr-plan/scripts/runtime/packages/protocol/registry/artifact-theme.json",
@@ -926,6 +926,22 @@
926
926
  "path": "rules/planr-spec/references/specification-contract.md",
927
927
  "digest": "sha256:c64ae73e88eff2cd2456b418add6de2658a10ec3230e99f37e298386cb8bba4b"
928
928
  },
929
+ {
930
+ "path": "rules/planr-sprint.mdc",
931
+ "digest": "sha256:ac9f56d5abe9b6443e4c246a501c0427c14403830e2756faa76c7f6fb48c0f85"
932
+ },
933
+ {
934
+ "path": "rules/planr-sprint/references/refinement-contract.md",
935
+ "digest": "sha256:0e2e621c0aa735b756187f28310f265be6a0330c790ecf71e27c527bad13cdcd"
936
+ },
937
+ {
938
+ "path": "rules/planr-sprint/references/sprint-formats.md",
939
+ "digest": "sha256:fc9620515dd2cfa1ecf9319c949bc491c620de9450e33f4e2ce08483023333c2"
940
+ },
941
+ {
942
+ "path": "rules/planr-sprint/schemas/refinement.schema.json",
943
+ "digest": "sha256:591bcd9bb94bbcbae0e3494f2e7f42a7ea953c90076254c1b290fa399901b690"
944
+ },
929
945
  {
930
946
  "path": "rules/planr-status.mdc",
931
947
  "digest": "sha256:2f762ca2e5710a034dc65d286327ad26b818b0c51a386a02562b9f9b65dd9d59"
@@ -939,5 +955,5 @@
939
955
  "digest": "sha256:6378ad3477e4be8b7e916c4249404c50cafecac1c70ffbf5a1a2fce195dfea16"
940
956
  }
941
957
  ],
942
- "contentDigest": "sha256:6513470ead50ff33f9e79a6bda9d3888397e90c3901f8183a7112176d892909a"
958
+ "contentDigest": "sha256:6159ae43e180fbc2950f3fe2804518e1a9590e3ef568627dc8b20770c9362f0d"
943
959
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openplanr",
3
3
  "version": "0.1.0",
4
- "ruleCount": 26,
4
+ "ruleCount": 27,
5
5
  "rules": [
6
6
  "rules/planr-artifact.mdc",
7
7
  "rules/planr-browser-qa.mdc",
@@ -27,6 +27,7 @@
27
27
  "rules/planr-release.mdc",
28
28
  "rules/planr-ship.mdc",
29
29
  "rules/planr-spec.mdc",
30
+ "rules/planr-sprint.mdc",
30
31
  "rules/planr-status.mdc",
31
32
  "rules/planr-sync.mdc"
32
33
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -26,6 +26,7 @@ Claude Code and `$planr:plan` in Codex). Do not perform the routed work here.
26
26
  | Create or check an architecture, process, sequence, or data diagram | `planr-diagram` |
27
27
  | Share, import, or export an HTML artifact review | `planr-artifact` |
28
28
  | Know what is done, pending, blocked, or next | `planr-status` |
29
+ | Refine the open backlog and select the sprint for the next release cut | `planr-sprint` |
29
30
  | See planning or Operate state in the browser | `planr-dashboard` |
30
31
  | Check artifacts for graph, status, or schema drift | `planr-sync` |
31
32
  | Judge release readiness or prepare a landing sequence | `planr-land` |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/protocol",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Canonical OpenPlanr schemas, registries, typed errors, and portable contract validation",
6
6
  "license": "MIT",
@@ -0,0 +1,154 @@
1
+ # Refinement contract
2
+
3
+ The refinement document is the durable record of one run: what was read, how
4
+ each item was judged, what was selected and what the refuters changed. The CLI
5
+ validates it (`planr sprint refinement <id> --data`), stores it as
6
+ `.planr/sprints/SPRINT-NNN/refinement.json`, renders `refinement.md` from it
7
+ and fills the sprint body from its batches. `planr sprint diff`, `planr sprint
8
+ close` and `planr sprint apply` read it back.
9
+
10
+ ## Item record
11
+
12
+ One entry per open item, whether or not it is selected.
13
+
14
+ | Field | Meaning |
15
+ | --- | --- |
16
+ | `id` | Artifact id (`BL-012`, `QT-034`, `TASK-007`). Only artifacts; file non-artifact work as a quick task first. |
17
+ | `title` | The item's title as written. |
18
+ | `claim` | What the item says is wrong or wanted, in one sentence. |
19
+ | `evidenceDate` | The latest dated evidence for the claim (`YYYY-MM-DD`), or `null` when none exists. |
20
+ | `codePath` / `codePathExists` | The code path the item names and whether it still exists on the default branch as described. `null` when the item names none. |
21
+ | `stale` | `true` when the evidence is older than the cadence allows or the code has moved on. |
22
+ | `blockedBy` | The named blockers: `partner: …`, `team decision: …`, `BL-045`. Empty when nothing blocks it. |
23
+ | `unblockQuestion` | The one question whose answer unblocks the item. |
24
+ | `effort` | `hours`, `day`, `days` or `week+`. |
25
+ | `score` | Production impact this month × tractability now. Any consistent scale; only the order matters. |
26
+ | `bucket` | `inProgress`, `planNext`, `blocked` or `closeOrDemote`. |
27
+ | `reason` | One clause: why the item sits in that bucket. |
28
+ | `evidence` | For close-or-demote rows: `file:line`, PR number or date. |
29
+ | `targetStatus` / `targetPriority` | What `planr sprint apply` writes, in the repository's own vocabulary (`planr update --help`). Priority applies to backlog items only. |
30
+
31
+ ## Scoring
32
+
33
+ Score = production impact this month × tractability now.
34
+
35
+ - Impact counts users hit, money or compliance at stake, and whether the
36
+ release cut depends on it. An item nobody is hit by this month scores low
37
+ regardless of its label.
38
+ - Tractability counts whether the fix is known, whether the code path exists,
39
+ whether a migration or a partner is needed, and whether the item is already
40
+ half done.
41
+ - Evidence date beats priority label. A P0 from months ago with no fresh
42
+ evidence is a candidate for close-or-demote, not for in progress.
43
+
44
+ ## Buckets
45
+
46
+ | Bucket | Rule |
47
+ | --- | --- |
48
+ | `inProgress` | Fits the stated capacity to the cut. Ordered for execution and grouped into `batches` (PR batches by product, or sessions). Includes the release cut itself as work. |
49
+ | `planNext` | Real and tractable, but after the cut. |
50
+ | `blocked` | Blocked on a partner, a team decision or another item. Never in progress. Carries `blockedBy` and `unblockQuestion`. |
51
+ | `closeOrDemote` | Dead, duplicated, overtaken or already delivered. Carries `evidence` and the `targetStatus` or `targetPriority` the write-back applies. |
52
+
53
+ Every item is in exactly one bucket; `buckets.<name>` lists the ids and each
54
+ item's `bucket` field agrees. `batches[].itemIds` partition `buckets.inProgress`
55
+ exactly.
56
+
57
+ ## Refuter lenses
58
+
59
+ Run all three over every in-progress pick before the buckets are shown.
60
+
61
+ | Lens | Question | Typical corrections |
62
+ | --- | --- | --- |
63
+ | `evidence` | Is it still real on the default branch? Is the premise true? Was it already fixed? | Dropped picks, moves to close-or-demote |
64
+ | `capacity` | Does the list fit the days? Are migrations, partner dependencies, PR batching and CI cost per PR accounted for? | Splits, reorders, moves to plan-next |
65
+ | `impact` | Who is hit this month if it is not done? Which higher-impact item was omitted for it? | Swaps, moves to plan-next |
66
+
67
+ A pick that fails a lens moves or drops, and the correction is recorded in
68
+ `refuted[]` as `{ itemId, lens, change, from, to }`. Nothing is deleted from
69
+ `items[]`; the item keeps its new bucket and reason.
70
+
71
+ ## `refinement.json`
72
+
73
+ ```json
74
+ {
75
+ "schemaVersion": 1,
76
+ "sprintId": "SPRINT-004",
77
+ "refinedAt": "2026-09-17",
78
+ "inputs": {
79
+ "capacityDays": 6,
80
+ "releaseCut": "2026-09-25",
81
+ "gitRevision": "a1b2c3d",
82
+ "previousSprintId": "SPRINT-003",
83
+ "operateCycleId": "OP-2026-09-A",
84
+ "sources": ["backlog", "quick", "git", "release-profile"],
85
+ "defaulted": ["capacity"],
86
+ "notes": "Connector not configured; statuses stay local."
87
+ },
88
+ "items": [
89
+ {
90
+ "id": "BL-345",
91
+ "title": "CRM callback silent since 10 Sep",
92
+ "claim": "Callbacks from the CRM stopped landing on 10 Sep",
93
+ "evidenceDate": "2026-09-16",
94
+ "codePath": "apps/apply/src/crm/callback.ts",
95
+ "codePathExists": true,
96
+ "stale": false,
97
+ "blockedBy": [],
98
+ "effort": "hours",
99
+ "score": 9.5,
100
+ "bucket": "inProgress",
101
+ "reason": "39 applications stuck at Received"
102
+ },
103
+ {
104
+ "id": "BL-295",
105
+ "title": "Importer drops trailing rows",
106
+ "evidenceDate": "2026-05-02",
107
+ "stale": true,
108
+ "blockedBy": [],
109
+ "effort": "days",
110
+ "score": 0.5,
111
+ "bucket": "closeOrDemote",
112
+ "reason": "delivered by #569",
113
+ "evidence": "PR #569 merged 2026-09-08",
114
+ "targetStatus": "closed"
115
+ },
116
+ {
117
+ "id": "BL-167",
118
+ "title": "Dynamics id for the Austrian Matura",
119
+ "evidenceDate": "2026-08-30",
120
+ "stale": false,
121
+ "blockedBy": ["partner: Dynamics team"],
122
+ "unblockQuestion": "Which Dynamics id represents the Austrian Matura?",
123
+ "effort": "day",
124
+ "score": 4,
125
+ "bucket": "blocked",
126
+ "reason": "needs the partner mapping"
127
+ }
128
+ ],
129
+ "buckets": {
130
+ "inProgress": ["BL-345"],
131
+ "planNext": [],
132
+ "blocked": ["BL-167"],
133
+ "closeOrDemote": ["BL-295"]
134
+ },
135
+ "batches": [
136
+ { "title": "VM read session", "effortDays": 0.5, "itemIds": ["BL-345"] }
137
+ ],
138
+ "refuted": [
139
+ {
140
+ "itemId": "BL-295",
141
+ "lens": "evidence",
142
+ "change": "delivered 8 Sep, moved to close",
143
+ "from": "inProgress",
144
+ "to": "closeOrDemote"
145
+ }
146
+ ]
147
+ }
148
+ ```
149
+
150
+ `inputs.sources` names what was read; `inputs.defaulted` names every value
151
+ taken from a default instead of the repository or the user. The CLI adds
152
+ `leftovers[]` on `planr sprint close` and `applied` on `planr sprint apply`;
153
+ never write those yourself. Unknown fields are rejected, so keep notes in
154
+ `inputs.notes` or in the item's `reason`.
@@ -0,0 +1,146 @@
1
+ # Sprint formats
2
+
3
+ Three durable outputs and one chat return. The CLI writes the first three from
4
+ the two JSON inputs below; when it is unavailable, write the same files by hand.
5
+
6
+ ## `sprint.json` (input to `planr sprint create --data`)
7
+
8
+ ```json
9
+ {
10
+ "title": "Cut 25 Sep 2026",
11
+ "startDate": "2026-09-17",
12
+ "releaseCut": "2026-09-25",
13
+ "capacityDays": 6,
14
+ "goals": ["Unblock stuck applications", "Ship the cut"]
15
+ }
16
+ ```
17
+
18
+ `endDate` defaults to `releaseCut`, or to `startDate` plus the duration when no
19
+ cut is known. `status` may be `planned` or `active` (default). Omit `taskIds`
20
+ and `batches`; `planr sprint refinement` fills them from the refinement
21
+ document.
22
+
23
+ ## Sprint artifact
24
+
25
+ `.planr/sprints/SPRINT-NNN-<slug>.md`: the existing frontmatter plus three
26
+ fields, and the In-progress bucket as checkboxes grouped by batch.
27
+
28
+ ```markdown
29
+ ---
30
+ id: "SPRINT-004"
31
+ name: "Cut 25 Sep 2026"
32
+ startDate: "2026-09-17"
33
+ endDate: "2026-09-25"
34
+ duration: "8d"
35
+ status: "active"
36
+ releaseCut: "2026-09-25"
37
+ capacityDays: 6
38
+ created: "2026-09-17"
39
+ updated: "2026-09-17"
40
+ taskIds: ["BL-345", "BL-348", "QT-194"]
41
+ refinedAt: "2026-09-17"
42
+ ---
43
+
44
+ # SPRINT-004: Cut 25 Sep 2026
45
+
46
+ ## Sprint Details
47
+
48
+ - **Duration:** 8d
49
+ - **Start:** 2026-09-17
50
+ - **End:** 2026-09-25
51
+ - **Status:** ACTIVE
52
+ - **Release cut:** 2026-09-25
53
+ - **Capacity:** 6 engineer-days
54
+
55
+ ## Tasks
56
+
57
+ ### VM read session · 0.5d
58
+
59
+ - [ ] **BL-345** CRM callback silent since 10 Sep · hours · [view](../backlog/BL-345-crm-callback-silent.md)
60
+
61
+ ### PR 1 · MUVi Apply · 1d
62
+
63
+ - [ ] **BL-348** rag-api cannot reach the department API · day · [view](../backlog/BL-348-rag-api.md)
64
+ - [ ] **QT-194** Release cut 25 Sep · hours · [view](../quick/QT-194-release-cut-25-sep.md)
65
+
66
+ ## Retrospective
67
+ _Complete this section when closing the sprint with `planr sprint close SPRINT-004`._
68
+ ```
69
+
70
+ Each task line is `- [ ] **ID** title · effort · [view](relative path)`.
71
+ `planr status`, `planr sprint close` and the dashboard read these lines; tick a
72
+ box when the item ships. `releaseCut` is absent when no release profile exists;
73
+ `capacityDays` and `refinedAt` are absent until a refinement is recorded.
74
+
75
+ ## Refinement note
76
+
77
+ `.planr/sprints/SPRINT-NNN/refinement.md`, rendered from the JSON so the next
78
+ run can diff against it:
79
+
80
+ - **Inputs**: capacity, release cut, git revision, previous sprint, Operate
81
+ cycle, sources read, values defaulted.
82
+ - **Items**: one table row per open item: `ID · score · evidence date · stale?
83
+ · blocked by · effort · bucket`.
84
+ - **Refuter verdicts**: every correction verbatim, with its lens.
85
+ - **In progress** by batch, then **Plan next**, **Blocked** and **Close or
86
+ demote** in full, since only In progress goes into the sprint.
87
+ - **Leftovers** (after `planr sprint close`) and **Applied** (after
88
+ `planr sprint apply`).
89
+
90
+ ## Machine-readable copy
91
+
92
+ `.planr/sprints/SPRINT-NNN/refinement.json`: the document described in
93
+ [the refinement contract](refinement-contract.md), validated against the JSON
94
+ Schema packaged as `schemas/refinement.schema.json` (linked from the skill
95
+ entrypoint). The dashboard, `planr sprint diff` and `planr sprint apply` consume
96
+ it.
97
+
98
+ ## Status write-back
99
+
100
+ Only on approval through the structured question. `planr sprint apply
101
+ SPRINT-NNN --yes --commit` writes each close, demote or blocked row's
102
+ `targetStatus`, `targetPriority` and `blockedBy` to the artifacts and commits the
103
+ sprint, the note, the JSON and the changed artifacts as one commit:
104
+
105
+ ```
106
+ chore(planr): refine backlog for SPRINT-NNN
107
+ ```
108
+
109
+ ## Example chat return
110
+
111
+ ```
112
+ Outcome: proposed · 5.8 of 6 engineer-days used · SPRINT-004 (cut 25 Sep)
113
+ Sprint: .planr/sprints/SPRINT-004-cut-25-sep-2026.md
114
+
115
+ In progress (execution order)
116
+ VM read session · 0.5d
117
+ BL-345 CRM callback silent since 10 Sep, 39 applications stuck at Received
118
+ BL-348 rag-api cannot reach the department API (+ missing api key)
119
+ PR 1 · MUVi Apply · 1d
120
+ BL-282 self-healing where clause
121
+ BL-229 write-side GUID check only (rest 9 Oct)
122
+ PR 2 · Connect residuals · 0.75d
123
+ BL-360, BL-364, BL-368, BL-056 (D3 only)
124
+ Ops readiness · 1.5d · QT-194 the cut · 0.5d
125
+
126
+ Plan next (9 Oct) BL-224, BL-043, BL-283, BL-014, BL-349 code, … (14 items)
127
+ Blocked BL-167 partner: Dynamics id for Austrian Matura?
128
+ BL-272 team: which English tests carry a score? (31 items)
129
+ Close or demote BL-295 done by #569 · BL-327 done by #590 · BL-197 P1 dead 14 Sep … (42 items)
130
+
131
+ Refuted BL-342 evidence: no server actions in muvi-apply, dropped
132
+ BL-229 impact: no applicant hit this month, split
133
+ BL-295 evidence: delivered 8 Sep, moved to close
134
+ Issues none
135
+ Next approve write-back: planr sprint apply SPRINT-004 --yes --commit
136
+ ```
137
+
138
+ ## Hand-written fallback
139
+
140
+ Without the CLI, create the three files above yourself: allocate the next
141
+ `SPRINT-NNN`, write the frontmatter and the batched checkboxes exactly as shown,
142
+ write `refinement.json` to the schema and `refinement.md` from it, and apply the
143
+ status changes with the repository's own vocabulary in one commit with the same
144
+ message. Never store notes as `.planr/sprints/SPRINT-NNN-*.md` siblings; graph
145
+ readers treat every `.md` in `sprints/` as a sprint and skip only the
146
+ `SPRINT-NNN/` directory.
@@ -0,0 +1,140 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openplanr.dev/schemas/skills/planr-sprint/refinement.schema.json",
4
+ "title": "OpenPlanr sprint refinement document",
5
+ "description": "One backlog refinement run: inputs, every open item's judgement, the four buckets, the in-progress batches and the refuter corrections. Written by the planr-sprint skill and validated by planr sprint refinement.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schemaVersion", "sprintId", "refinedAt", "inputs", "items", "buckets"],
9
+ "$defs": {
10
+ "isoDate": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
11
+ "artifactId": { "type": "string", "pattern": "^[A-Z]+-\\d+$" },
12
+ "sprintId": { "type": "string", "pattern": "^SPRINT-\\d+$" },
13
+ "text": { "type": "string", "minLength": 1 },
14
+ "bucket": { "enum": ["inProgress", "planNext", "blocked", "closeOrDemote"] },
15
+ "effort": { "enum": ["hours", "day", "days", "week+"] },
16
+ "lens": { "enum": ["evidence", "capacity", "impact"] },
17
+ "idList": { "type": "array", "items": { "$ref": "#/$defs/artifactId" } }
18
+ },
19
+ "properties": {
20
+ "schemaVersion": { "const": 1 },
21
+ "sprintId": { "$ref": "#/$defs/sprintId" },
22
+ "refinedAt": { "$ref": "#/$defs/isoDate" },
23
+ "inputs": {
24
+ "type": "object",
25
+ "additionalProperties": false,
26
+ "properties": {
27
+ "capacityDays": { "type": "number", "exclusiveMinimum": 0 },
28
+ "releaseCut": { "$ref": "#/$defs/isoDate" },
29
+ "gitRevision": { "$ref": "#/$defs/text" },
30
+ "previousSprintId": { "$ref": "#/$defs/sprintId" },
31
+ "operateCycleId": { "$ref": "#/$defs/text" },
32
+ "sources": { "type": "array", "items": { "$ref": "#/$defs/text" }, "default": [] },
33
+ "defaulted": { "type": "array", "items": { "$ref": "#/$defs/text" }, "default": [] },
34
+ "notes": { "$ref": "#/$defs/text" }
35
+ }
36
+ },
37
+ "items": {
38
+ "type": "array",
39
+ "items": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": ["id", "title", "effort", "score", "bucket", "reason"],
43
+ "properties": {
44
+ "id": { "$ref": "#/$defs/artifactId" },
45
+ "title": { "$ref": "#/$defs/text" },
46
+ "claim": { "$ref": "#/$defs/text" },
47
+ "evidenceDate": { "oneOf": [{ "$ref": "#/$defs/isoDate" }, { "type": "null" }], "default": null },
48
+ "codePath": { "oneOf": [{ "$ref": "#/$defs/text" }, { "type": "null" }] },
49
+ "codePathExists": { "type": ["boolean", "null"] },
50
+ "stale": { "type": "boolean", "default": false },
51
+ "blockedBy": { "type": "array", "items": { "$ref": "#/$defs/text" }, "default": [] },
52
+ "unblockQuestion": { "$ref": "#/$defs/text" },
53
+ "effort": { "$ref": "#/$defs/effort" },
54
+ "score": { "type": "number" },
55
+ "bucket": { "$ref": "#/$defs/bucket" },
56
+ "reason": { "$ref": "#/$defs/text" },
57
+ "evidence": { "$ref": "#/$defs/text" },
58
+ "targetStatus": { "$ref": "#/$defs/text" },
59
+ "targetPriority": { "$ref": "#/$defs/text" }
60
+ }
61
+ }
62
+ },
63
+ "buckets": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": ["inProgress", "planNext", "blocked", "closeOrDemote"],
67
+ "properties": {
68
+ "inProgress": { "$ref": "#/$defs/idList" },
69
+ "planNext": { "$ref": "#/$defs/idList" },
70
+ "blocked": { "$ref": "#/$defs/idList" },
71
+ "closeOrDemote": { "$ref": "#/$defs/idList" }
72
+ }
73
+ },
74
+ "batches": {
75
+ "type": "array",
76
+ "default": [],
77
+ "items": {
78
+ "type": "object",
79
+ "additionalProperties": false,
80
+ "required": ["title", "itemIds"],
81
+ "properties": {
82
+ "title": { "$ref": "#/$defs/text" },
83
+ "effortDays": { "type": "number", "exclusiveMinimum": 0 },
84
+ "itemIds": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/artifactId" } }
85
+ }
86
+ }
87
+ },
88
+ "refuted": {
89
+ "type": "array",
90
+ "default": [],
91
+ "items": {
92
+ "type": "object",
93
+ "additionalProperties": false,
94
+ "required": ["itemId", "lens", "change"],
95
+ "properties": {
96
+ "itemId": { "$ref": "#/$defs/artifactId" },
97
+ "lens": { "$ref": "#/$defs/lens" },
98
+ "change": { "$ref": "#/$defs/text" },
99
+ "from": { "$ref": "#/$defs/bucket" },
100
+ "to": { "enum": ["inProgress", "planNext", "blocked", "closeOrDemote", "dropped"] }
101
+ }
102
+ }
103
+ },
104
+ "leftovers": {
105
+ "description": "Written by planr sprint close.",
106
+ "type": "array",
107
+ "items": {
108
+ "type": "object",
109
+ "additionalProperties": false,
110
+ "required": ["id", "reason"],
111
+ "properties": {
112
+ "id": { "$ref": "#/$defs/artifactId" },
113
+ "reason": { "enum": ["unchecked", "not-done"] }
114
+ }
115
+ }
116
+ },
117
+ "applied": {
118
+ "description": "Written by planr sprint apply.",
119
+ "type": "object",
120
+ "additionalProperties": false,
121
+ "required": ["at", "updates"],
122
+ "properties": {
123
+ "at": { "$ref": "#/$defs/text" },
124
+ "updates": {
125
+ "type": "array",
126
+ "items": {
127
+ "type": "object",
128
+ "additionalProperties": false,
129
+ "required": ["id", "type", "fields"],
130
+ "properties": {
131
+ "id": { "$ref": "#/$defs/artifactId" },
132
+ "type": { "$ref": "#/$defs/text" },
133
+ "fields": { "type": "object", "additionalProperties": { "type": "string" } }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }