devague 0.4.0__tar.gz → 0.5.0__tar.gz

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 (112) hide show
  1. {devague-0.4.0 → devague-0.5.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +13 -41
  2. {devague-0.4.0 → devague-0.5.0}/.claude/skills/think/SKILL.md +38 -16
  3. {devague-0.4.0 → devague-0.5.0}/.claude/skills/think/scripts/think.sh +13 -47
  4. devague-0.5.0/.devague/current_plan +1 -0
  5. devague-0.5.0/.devague/frames/devague-now-ships-a-documented-spec-contract-every.json +263 -0
  6. devague-0.5.0/.devague/plans/devague-now-ships-a-documented-spec-contract-every.json +363 -0
  7. {devague-0.4.0 → devague-0.5.0}/CHANGELOG.md +28 -0
  8. {devague-0.4.0 → devague-0.5.0}/CLAUDE.md +9 -0
  9. {devague-0.4.0 → devague-0.5.0}/PKG-INFO +1 -1
  10. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/capture.py +9 -1
  11. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/converge.py +18 -7
  12. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/export.py +2 -2
  13. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/plan.py +20 -12
  14. {devague-0.4.0 → devague-0.5.0}/devague/cli/_frames.py +16 -1
  15. devague-0.5.0/devague/convergence.py +149 -0
  16. {devague-0.4.0 → devague-0.5.0}/devague/frame.py +45 -1
  17. {devague-0.4.0 → devague-0.5.0}/devague/plan_convergence.py +47 -3
  18. {devague-0.4.0 → devague-0.5.0}/devague/render/frame_md.py +3 -3
  19. {devague-0.4.0 → devague-0.5.0}/devague/render/plan_md.py +11 -7
  20. {devague-0.4.0 → devague-0.5.0}/devague/render/spec_md.py +14 -12
  21. {devague-0.4.0 → devague-0.5.0}/devague/store.py +11 -1
  22. devague-0.5.0/docs/examples/contract-example.json +160 -0
  23. devague-0.5.0/docs/plans/devague-now-ships-a-documented-spec-contract-every.md +85 -0
  24. devague-0.5.0/docs/reviews/spec-contract-frame-review.md +150 -0
  25. devague-0.5.0/docs/spec-contract.md +180 -0
  26. devague-0.5.0/docs/specs/devague-now-ships-a-documented-spec-contract-every.md +55 -0
  27. {devague-0.4.0 → devague-0.5.0}/pyproject.toml +1 -1
  28. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_converge_export.py +7 -7
  29. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_moves.py +27 -0
  30. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_plan.py +3 -3
  31. devague-0.5.0/tests/test_contract.py +129 -0
  32. devague-0.5.0/tests/test_convergence.py +97 -0
  33. devague-0.5.0/tests/test_frame.py +111 -0
  34. devague-0.5.0/tests/test_offline.py +58 -0
  35. {devague-0.4.0 → devague-0.5.0}/tests/test_plan_convergence.py +14 -14
  36. devague-0.5.0/tests/test_render.py +81 -0
  37. {devague-0.4.0 → devague-0.5.0}/tests/test_render_plan.py +7 -0
  38. {devague-0.4.0 → devague-0.5.0}/tests/test_store.py +43 -1
  39. {devague-0.4.0 → devague-0.5.0}/uv.lock +1 -1
  40. devague-0.4.0/devague/convergence.py +0 -72
  41. devague-0.4.0/tests/test_convergence.py +0 -62
  42. devague-0.4.0/tests/test_frame.py +0 -42
  43. devague-0.4.0/tests/test_render.py +0 -41
  44. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/SKILL.md +0 -0
  45. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
  46. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
  47. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
  48. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
  49. {devague-0.4.0 → devague-0.5.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
  50. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/SKILL.md +0 -0
  51. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
  52. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
  53. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
  54. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
  55. {devague-0.4.0 → devague-0.5.0}/.claude/skills/communicate/scripts/templates/skill-update-brief.md +0 -0
  56. {devague-0.4.0 → devague-0.5.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
  57. {devague-0.4.0 → devague-0.5.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
  58. {devague-0.4.0 → devague-0.5.0}/.claude/skills/run-tests/SKILL.md +0 -0
  59. {devague-0.4.0 → devague-0.5.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  60. {devague-0.4.0 → devague-0.5.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
  61. {devague-0.4.0 → devague-0.5.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
  62. {devague-0.4.0 → devague-0.5.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
  63. {devague-0.4.0 → devague-0.5.0}/.claude/skills/version-bump/SKILL.md +0 -0
  64. {devague-0.4.0 → devague-0.5.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
  65. {devague-0.4.0 → devague-0.5.0}/.claude/skills.local.yaml.example +0 -0
  66. {devague-0.4.0 → devague-0.5.0}/.flake8 +0 -0
  67. {devague-0.4.0 → devague-0.5.0}/.github/workflows/publish.yml +0 -0
  68. {devague-0.4.0 → devague-0.5.0}/.github/workflows/security-checks.yml +0 -0
  69. {devague-0.4.0 → devague-0.5.0}/.github/workflows/tests.yml +0 -0
  70. {devague-0.4.0 → devague-0.5.0}/.gitignore +0 -0
  71. {devague-0.4.0 → devague-0.5.0}/.markdownlint-cli2.yaml +0 -0
  72. {devague-0.4.0 → devague-0.5.0}/.pre-commit-config.yaml +0 -0
  73. {devague-0.4.0 → devague-0.5.0}/LICENSE +0 -0
  74. {devague-0.4.0 → devague-0.5.0}/README.md +0 -0
  75. {devague-0.4.0 → devague-0.5.0}/culture.yaml +0 -0
  76. {devague-0.4.0 → devague-0.5.0}/devague/__init__.py +0 -0
  77. {devague-0.4.0 → devague-0.5.0}/devague/__main__.py +0 -0
  78. {devague-0.4.0 → devague-0.5.0}/devague/cli/__init__.py +0 -0
  79. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/__init__.py +0 -0
  80. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/confirm.py +0 -0
  81. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/explain.py +0 -0
  82. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/interrogate.py +0 -0
  83. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/learn.py +0 -0
  84. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/list_frames.py +0 -0
  85. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/new.py +0 -0
  86. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/park.py +0 -0
  87. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/reject.py +0 -0
  88. {devague-0.4.0 → devague-0.5.0}/devague/cli/_commands/show.py +0 -0
  89. {devague-0.4.0 → devague-0.5.0}/devague/cli/_errors.py +0 -0
  90. {devague-0.4.0 → devague-0.5.0}/devague/cli/_output.py +0 -0
  91. {devague-0.4.0 → devague-0.5.0}/devague/cli/_plans.py +0 -0
  92. {devague-0.4.0 → devague-0.5.0}/devague/plan.py +0 -0
  93. {devague-0.4.0 → devague-0.5.0}/devague/plan_store.py +0 -0
  94. {devague-0.4.0 → devague-0.5.0}/devague/render/__init__.py +0 -0
  95. {devague-0.4.0 → devague-0.5.0}/docs/skill-sources.md +0 -0
  96. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/plans/2026-05-22-specifix-onboarding.md +0 -0
  97. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/plans/2026-05-23-devague-rename.md +0 -0
  98. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/plans/2026-05-23-devague-working-backwards-engine.md +0 -0
  99. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/specs/2026-05-22-specifix-onboarding-design.md +0 -0
  100. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/specs/2026-05-23-devague-spec-to-plan-design.md +0 -0
  101. {devague-0.4.0 → devague-0.5.0}/docs/superpowers/specs/2026-05-23-devague-working-backwards-design.md +0 -0
  102. {devague-0.4.0 → devague-0.5.0}/sonar-project.properties +0 -0
  103. {devague-0.4.0 → devague-0.5.0}/tests/__init__.py +0 -0
  104. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_affordances.py +0 -0
  105. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_chassis.py +0 -0
  106. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_errors.py +0 -0
  107. {devague-0.4.0 → devague-0.5.0}/tests/test_cli_output.py +0 -0
  108. {devague-0.4.0 → devague-0.5.0}/tests/test_package.py +0 -0
  109. {devague-0.4.0 → devague-0.5.0}/tests/test_plan.py +0 -0
  110. {devague-0.4.0 → devague-0.5.0}/tests/test_plan_store.py +0 -0
  111. {devague-0.4.0 → devague-0.5.0}/tests/test_spec_to_plan_skill.py +0 -0
  112. {devague-0.4.0 → devague-0.5.0}/tests/test_think_skill.py +0 -0
@@ -108,7 +108,6 @@ cmd_status() {
108
108
  python3 - <<'PY'
109
109
  import json
110
110
  import os
111
- import re
112
111
  import sys
113
112
 
114
113
 
@@ -154,52 +153,25 @@ if conv is None:
154
153
  print("next move: devague plan show # inspect the plan")
155
154
  sys.exit(0)
156
155
 
157
- if conv.get("passed"):
156
+ if conv.get("ready_for_plan"):
158
157
  print("convergence: PASSED ✓")
158
+ for w in conv.get("warnings") or []:
159
+ print(f" ⚠ {w}")
159
160
  print("next move: devague plan export # write the buildable plan")
160
161
  sys.exit(0)
161
162
 
162
- missing = conv.get("missing") or []
163
- print(f"convergence: NOT passed — {len(missing)} gap(s):")
164
- for gap in missing:
165
- print(f" - {gap}")
166
-
167
-
168
- def suggest(gap):
169
- if "no tasks yet" in gap:
170
- return 'devague plan task "<summary>" --covers <c*/h*> --accept "<criterion>"'
171
- m = re.search(r"coverage target (\w+) ", gap)
172
- if m:
173
- tid = m.group(1)
174
- return (
175
- f'cover {tid}: devague plan task "<summary>" --covers {tid} --accept "<...>"'
176
- f" (or: devague plan cover <tN> --target {tid})"
177
- )
178
- m = re.search(r"task (t\d+) has no acceptance", gap)
179
- if m:
180
- return f'devague plan accept {m.group(1)} "<acceptance criterion>"'
181
- m = re.search(r"task (t\d+) still proposed", gap)
182
- if m:
183
- tid = m.group(1)
184
- return (
185
- f"this is an LLM proposal — the USER decides:"
186
- f" devague plan confirm {tid} (or: devague plan reject {tid})"
187
- )
188
- m = re.search(r"task (t\d+) depends on unknown task (t\d+)", gap)
189
- if m:
190
- return f"fix {m.group(1)}'s dependency on missing {m.group(2)} (add it, or drop the dep)"
191
- if "dependency cycle" in gap:
192
- return "break the dependency cycle: re-point one task's --dep so the graph is acyclic"
193
- m = re.search(r"blocking risk (r\d+)", gap)
194
- if m:
195
- return f"resolve {m.group(1)}: cover it with a task, or re-record it as non-blocking"
196
- return "devague plan show # inspect and decide"
197
-
198
-
199
- if missing:
163
+ blockers = conv.get("blockers") or []
164
+ print(f"convergence: NOT passed — {len(blockers)} gap(s):")
165
+ for b in blockers:
166
+ print(f" - {b}")
167
+ for w in conv.get("warnings") or []:
168
+ print(f" ⚠ {w}")
169
+
170
+ moves = conv.get("required_next_moves") or []
171
+ if moves:
200
172
  print()
201
173
  print("recommended next move (first gap):")
202
- print(f" {suggest(missing[0])}")
174
+ print(f" {moves[0]}")
203
175
  PY
204
176
  }
205
177
 
@@ -66,27 +66,31 @@ portable resolution and the `status` helper.
66
66
  | `learn` / `explain <move>` | Teach the method / explain one move. |
67
67
 
68
68
  Claim kinds: `announcement`, `audience`, `after_state`, `before_state`,
69
- `why_it_matters`, `boundary`, `success_signal`, `open_question`. Vagueness kinds:
70
- `unknown_nonblocking`, `unknown_blocking`, `out_of_scope`, `follow_up`.
69
+ `why_it_matters`, `boundary`, `success_signal`, `open_question`, `non_goal`,
70
+ `requirement`, `assumption`, `decision`. Vagueness kinds: `unknown_nonblocking`,
71
+ `unknown_blocking`, `out_of_scope`, `follow_up`.
71
72
 
72
73
  These are exactly the kinds the **shipped CLI enforces** (`CLAIM_KINDS` /
73
74
  `VAGUENESS_KINDS` in `devague/frame.py`) — the skill documents the surface as
74
- built, so every command here passes the CLI's `choices=` validation. A fuller
75
- proposed type/state set, plus the formal per-move input/output/transition
76
- contract, is tracked on the CLI side in
77
- [#5](https://github.com/agentculture/devague/issues/5); for the authoritative
75
+ built, so every command here passes the CLI's `choices=` validation. `requirement`
76
+ is spec-affecting (needs a confirmed honesty condition); `non_goal` / `decision`
77
+ are descriptive; an unconfirmed `assumption` is a convergence *warning*, not a
78
+ blocker. The formal entity model, the `(state × origin)` vocabulary, and the
79
+ per-move input/output/transition/error contract are documented in
80
+ [`docs/spec-contract.md`](../../../docs/spec-contract.md) (issue
81
+ [#5](https://github.com/agentculture/devague/issues/5)); for the authoritative
78
82
  live shape of any move, run it with `--json` (or `devague learn --json` /
79
- `devague explain <move>`). When the CLI's contract grows, re-sync this list.
83
+ `devague explain <move>`).
80
84
 
81
85
  ### `status` — the next-move helper
82
86
 
83
87
  `status` is a wrapper-only verb (the CLI has no `status`). It reads
84
88
  `converge --json` + `list --json` and prints where the current frame stands, the
85
- remaining gaps, and the recommended next move derived from the first gap.
86
- `converge --json` currently emits `{passed, missing}`, which is what the helper
87
- consumes; if [#5](https://github.com/agentculture/devague/issues/5) enriches that
88
- payload (e.g. structured `blockers` / `warnings` / `required_next_moves`),
89
- `status` will surface the richer fields then.
89
+ remaining gaps, and the recommended next move. `converge --json` emits the
90
+ structured result `{ready_for_spec, blockers, warnings, parked_items,
91
+ required_next_moves}` (issue [#5](https://github.com/agentculture/devague/issues/5));
92
+ the helper reads `ready_for_spec`, lists the `blockers` and `warnings`, and shows
93
+ `required_next_moves[0]` as the recommended move — no longer deriving it itself.
90
94
 
91
95
  ```text
92
96
  frame: my-feature (1 frame total)
@@ -155,10 +159,28 @@ d converge # gate; resolve any listed gaps
155
159
  d export # writes docs/specs/<slug>.md once converged
156
160
  ```
157
161
 
158
- The exported spec-md is a buildable artifact. The next leg is the sibling
159
- **`/spec-to-plan`** skill: `devague plan new --frame <slug>` seeds a plan from the
160
- converged frame and works it forward into a buildable plan (it can equally feed
161
- `superpowers:writing-plans` or a normal implementation PR).
162
+ The exported spec-md is a buildable artifact.
163
+
164
+ ## After export commit, then hand off
165
+
166
+ Once `export` writes the spec **and the user has reviewed it**, close the
167
+ idea→spec leg cleanly before moving on:
168
+
169
+ 1. **Commit the spec.** Commit the exported `docs/specs/<slug>.md` (along with
170
+ the `.devague/<slug>.json` frame state and any review artifact under
171
+ `docs/reviews/`) so the converged frame is durable in history, not just on
172
+ disk. Use a focused message, e.g. `git commit -m "spec: <slug> (devague
173
+ /think)"`. The frame and the spec are the evidence trail for every confirmed
174
+ claim — keep them together. (Per the repo's standing convention this normally
175
+ becomes a branch + PR via the `cicd` skill; commit-only is fine when the user
176
+ asks for it.)
177
+ 2. **Hand off to `/spec-to-plan`.** The forward leg is the sibling skill:
178
+ `devague plan new --frame <slug>` seeds a plan from the converged frame and
179
+ works it forward into a buildable plan (it can equally feed
180
+ `superpowers:writing-plans` or a normal implementation PR).
181
+
182
+ Don't pause for a "what next?" menu after a reviewed export — the standing flow
183
+ is **commit, then `/spec-to-plan`**.
162
184
 
163
185
  ## Provenance
164
186
 
@@ -114,7 +114,6 @@ cmd_status() {
114
114
  python3 - <<'PY'
115
115
  import json
116
116
  import os
117
- import re
118
117
  import sys
119
118
 
120
119
 
@@ -161,58 +160,25 @@ if conv is None:
161
160
  print("next move: devague show # inspect the frame")
162
161
  sys.exit(0)
163
162
 
164
- if conv.get("passed"):
163
+ if conv.get("ready_for_spec"):
165
164
  print("convergence: PASSED ✓")
165
+ for w in conv.get("warnings") or []:
166
+ print(f" ⚠ {w}")
166
167
  print("next move: devague export # write the buildable spec")
167
168
  sys.exit(0)
168
169
 
169
- missing = conv.get("missing") or []
170
- print(f"convergence: NOT passed — {len(missing)} gap(s):")
171
- for gap in missing:
172
- print(f" - {gap}")
173
-
174
-
175
- def suggest(gap):
176
- # Confirmation is a USER-only transition; a plain (user-origin) capture
177
- # is already confirmed, so never imply the agent should confirm its own
178
- # work. Spell out who confirms wherever a confirm is in play.
179
- m = re.search(r"missing confirmed '([a-z_]+)' claim", gap)
180
- if m:
181
- kind = m.group(1)
182
- return (f'devague capture --kind {kind} "<text>"'
183
- f' (a user capture auto-confirms; an --origin llm capture'
184
- f' then needs the USER to confirm it)')
185
- if "before_state" in gap and "why_it_matters" in gap:
186
- return 'devague capture --kind why_it_matters "<text>"'
187
- if "boundary" in gap:
188
- return 'devague capture --kind boundary "<text>"'
189
- if "success_signal" in gap:
190
- return 'devague capture --kind success_signal "<text>"'
191
- m = re.search(r"claim (c\d+) still proposed", gap)
192
- if m:
193
- cid = m.group(1)
194
- return (f'this is an LLM proposal — the USER decides:'
195
- f' devague confirm {cid} (or: devague reject {cid})')
196
- m = re.search(r"claim (c\d+) has no confirmed honesty condition", gap)
197
- if m:
198
- cid = m.group(1)
199
- return (f'devague interrogate {cid} --honesty "<what must be true>"'
200
- f' then the USER runs: devague confirm <hN>')
201
- m = re.search(r"blocking vagueness (v\d+)", gap)
202
- if m:
203
- return (f"resolve {m.group(1)}: capture+confirm the answer, "
204
- f"or re-park it as non-blocking")
205
- m = re.search(r"blocking hard question (q\d+) on (c\d+)", gap)
206
- if m:
207
- return (f"resolve {m.group(1)} on {m.group(2)}: answer it, then "
208
- f"capture/confirm the resulting claim")
209
- return "devague show # inspect and decide"
210
-
211
-
212
- if missing:
170
+ blockers = conv.get("blockers") or []
171
+ print(f"convergence: NOT passed — {len(blockers)} gap(s):")
172
+ for b in blockers:
173
+ print(f" - {b}")
174
+ for w in conv.get("warnings") or []:
175
+ print(f" ⚠ {w}")
176
+
177
+ moves = conv.get("required_next_moves") or []
178
+ if moves:
213
179
  print()
214
180
  print("recommended next move (first gap):")
215
- print(f" {suggest(missing[0])}")
181
+ print(f" {moves[0]}")
216
182
  PY
217
183
  }
218
184
 
@@ -0,0 +1 @@
1
+ devague-now-ships-a-documented-spec-contract-every
@@ -0,0 +1,263 @@
1
+ {
2
+ "slug": "devague-now-ships-a-documented-spec-contract-every",
3
+ "title": "Devague now ships a documented spec contract: every frame is a durable, reloadable artifact, and converge returns a structured result (ready_for_spec, blockers, warnings, parked_items, required_next_moves) instead of prose-only advice",
4
+ "status": "exported",
5
+ "created": "2026-05-23T08:08:13Z",
6
+ "updated": "2026-05-23T09:17:12Z",
7
+ "claims": [
8
+ {
9
+ "id": "c1",
10
+ "kind": "announcement",
11
+ "text": "Devague now ships a documented spec contract: every frame is a durable, reloadable artifact, and converge returns a structured result (ready_for_spec, blockers, warnings, parked_items, required_next_moves) instead of prose-only advice",
12
+ "origin": "user",
13
+ "status": "confirmed",
14
+ "honesty_conditions": [
15
+ {
16
+ "id": "h1",
17
+ "text": "A frame round-trips losslessly (save then load yields an identical frame) including schema_version, the new claim types, and the structured convergence payload; existing 0.4.0 frames still load",
18
+ "status": "confirmed"
19
+ }
20
+ ],
21
+ "hard_questions": [],
22
+ "links": []
23
+ },
24
+ {
25
+ "id": "c2",
26
+ "kind": "audience",
27
+ "text": "Devague and the assisting LLM that drives it \u2014 they coordinate around structured feature-framing state without a rigid wizard",
28
+ "origin": "user",
29
+ "status": "confirmed",
30
+ "honesty_conditions": [
31
+ {
32
+ "id": "h2",
33
+ "text": "Every move accepts and emits documented JSON, and the contract spells out per-move input / output / state-transition / validation-errors so an LLM can drive devague without guessing internal state",
34
+ "status": "confirmed"
35
+ }
36
+ ],
37
+ "hard_questions": [],
38
+ "links": []
39
+ },
40
+ {
41
+ "id": "c3",
42
+ "kind": "after_state",
43
+ "text": "A vague idea becomes a claim-based, pressure-tested, buildable spec held in a durable, reloadable artifact whose entities are validated",
44
+ "origin": "user",
45
+ "status": "confirmed",
46
+ "honesty_conditions": [
47
+ {
48
+ "id": "h3",
49
+ "text": "Matches shipped 0.4.0 reality \u2014 converge --json emits {passed, missing} today and no contract doc is committed (verifiable in the repo before relying on it)",
50
+ "status": "confirmed"
51
+ }
52
+ ],
53
+ "hard_questions": [],
54
+ "links": []
55
+ },
56
+ {
57
+ "id": "c4",
58
+ "kind": "before_state",
59
+ "text": "Framing state is partly implicit and undocumented; converge returns prose-only advice ({passed, missing}); there is no documented contract an LLM can rely on",
60
+ "origin": "user",
61
+ "status": "confirmed",
62
+ "honesty_conditions": [
63
+ {
64
+ "id": "h4",
65
+ "text": "The contract is enforced by validation on load: a schema-violating frame is rejected with a clear, actionable error rather than silently accepted",
66
+ "status": "confirmed"
67
+ }
68
+ ],
69
+ "hard_questions": [],
70
+ "links": []
71
+ },
72
+ {
73
+ "id": "c5",
74
+ "kind": "why_it_matters",
75
+ "text": "An LLM and devague can only coordinate reliably around a contract that is documented, validated, and machine-readable \u2014 convergence must mean something, not vibes",
76
+ "origin": "user",
77
+ "status": "confirmed",
78
+ "honesty_conditions": [
79
+ {
80
+ "id": "h5",
81
+ "text": "Convergence stays evidence-based and export stays gated on converge passing; the gate is computed only from confirmed claims and confirmed honesty conditions, never a hunch",
82
+ "status": "confirmed"
83
+ }
84
+ ],
85
+ "hard_questions": [],
86
+ "links": []
87
+ },
88
+ {
89
+ "id": "c6",
90
+ "kind": "boundary",
91
+ "text": "Not a full PRD generator and not a fixed wizard; the move-driven, deterministic model stays",
92
+ "origin": "user",
93
+ "status": "confirmed",
94
+ "honesty_conditions": [
95
+ {
96
+ "id": "h6",
97
+ "text": "The deterministic move-driven model is preserved: no fixed prompt sequence is added; the CLI stays a state tracker and the LLM still chooses the next move",
98
+ "status": "confirmed"
99
+ }
100
+ ],
101
+ "hard_questions": [],
102
+ "links": []
103
+ },
104
+ {
105
+ "id": "c7",
106
+ "kind": "boundary",
107
+ "text": "The local contract requires no GitHub, agents, or external services",
108
+ "origin": "user",
109
+ "status": "confirmed",
110
+ "honesty_conditions": [
111
+ {
112
+ "id": "h7",
113
+ "text": "Every contract operation (create / load / mutate / show / converge / export) runs fully offline against local .devague/ state with zero network calls",
114
+ "status": "confirmed"
115
+ }
116
+ ],
117
+ "hard_questions": [],
118
+ "links": []
119
+ },
120
+ {
121
+ "id": "c8",
122
+ "kind": "boundary",
123
+ "text": "Convergence is never claimed on vibes, and LLM-proposed content is never silently promoted to confirmed truth",
124
+ "origin": "user",
125
+ "status": "confirmed",
126
+ "honesty_conditions": [
127
+ {
128
+ "id": "h8",
129
+ "text": "LLM-proposed claims and honesty conditions persist as proposed (origin=llm) and require an explicit user confirm before they affect convergence \u2014 nothing auto-confirms",
130
+ "status": "confirmed"
131
+ }
132
+ ],
133
+ "hard_questions": [],
134
+ "links": []
135
+ },
136
+ {
137
+ "id": "c9",
138
+ "kind": "success_signal",
139
+ "text": "converge returns a structured result (ready_for_spec, blockers, warnings, parked_items, required_next_moves) with blockers instead of prose-only advice",
140
+ "origin": "user",
141
+ "status": "confirmed",
142
+ "honesty_conditions": [
143
+ {
144
+ "id": "h9",
145
+ "text": "converge --json emits ONLY the new structured shape {ready_for_spec, blockers, warnings, parked_items, required_next_moves} (hard break); the skill's status helper is updated in the same change; blockers block convergence and warnings do not",
146
+ "status": "confirmed"
147
+ }
148
+ ],
149
+ "hard_questions": [],
150
+ "links": []
151
+ },
152
+ {
153
+ "id": "c10",
154
+ "kind": "success_signal",
155
+ "text": "A documented spec contract exists in the repo, with worked contract examples for at least one feature frame",
156
+ "origin": "user",
157
+ "status": "confirmed",
158
+ "honesty_conditions": [
159
+ {
160
+ "id": "h10",
161
+ "text": "The committed contract doc is the source of truth for kinds / states / fields / transitions and includes at least one worked frame example the CLI can actually round-trip",
162
+ "status": "confirmed"
163
+ }
164
+ ],
165
+ "hard_questions": [],
166
+ "links": []
167
+ },
168
+ {
169
+ "id": "c11",
170
+ "kind": "success_signal",
171
+ "text": "The CLI can create, load, mutate, and display a frame locally; core entities are validated",
172
+ "origin": "user",
173
+ "status": "confirmed",
174
+ "honesty_conditions": [
175
+ {
176
+ "id": "h11",
177
+ "text": "create / load / mutate / show round-trip through the JSON store under validation, and the demonstrated operations are covered by passing tests",
178
+ "status": "confirmed"
179
+ }
180
+ ],
181
+ "hard_questions": [],
182
+ "links": []
183
+ },
184
+ {
185
+ "id": "c12",
186
+ "kind": "success_signal",
187
+ "text": "Tests cover claim provenance, honesty-condition confirmation, parking vagueness, and convergence failure",
188
+ "origin": "user",
189
+ "status": "confirmed",
190
+ "honesty_conditions": [
191
+ {
192
+ "id": "h12",
193
+ "text": "Each of the four areas (provenance, honesty-condition confirmation, parking vagueness, convergence failure) has at least one test asserting the contract behavior, all green in CI",
194
+ "status": "confirmed"
195
+ }
196
+ ],
197
+ "hard_questions": [],
198
+ "links": []
199
+ },
200
+ {
201
+ "id": "c13",
202
+ "kind": "boundary",
203
+ "text": "The contract formalizes 0.4.0's shipped vocabulary as canonical \u2014 state in {proposed,confirmed,rejected,parked} x origin in {user,llm}; no rename and no migration of existing frames",
204
+ "origin": "user",
205
+ "status": "confirmed",
206
+ "honesty_conditions": [
207
+ {
208
+ "id": "h13",
209
+ "text": "The doc maps the issue's proposed names (llm_proposed, user_confirmed, intentionally_out_of_scope, ...) onto the shipped (state x origin) model so no information is lost and no rename is required",
210
+ "status": "confirmed"
211
+ }
212
+ ],
213
+ "hard_questions": [],
214
+ "links": []
215
+ },
216
+ {
217
+ "id": "c14",
218
+ "kind": "success_signal",
219
+ "text": "The claim-type vocabulary adds non_goal, requirement, assumption, and decision to the shipped set, each with a documented convergence-gate impact",
220
+ "origin": "user",
221
+ "status": "confirmed",
222
+ "honesty_conditions": [
223
+ {
224
+ "id": "h14",
225
+ "text": "Each new type's gate impact is documented and tested: requirement is spec-affecting (needs a confirmed honesty condition like other claims); non_goal and decision are descriptive (non-blocking); an unconfirmed assumption surfaces as a warning, not a blocker",
226
+ "status": "confirmed"
227
+ }
228
+ ],
229
+ "hard_questions": [],
230
+ "links": []
231
+ },
232
+ {
233
+ "id": "c15",
234
+ "kind": "success_signal",
235
+ "text": "Every frame carries a schema_version field; load validates by version so existing frames keep loading as the schema grows",
236
+ "origin": "user",
237
+ "status": "confirmed",
238
+ "honesty_conditions": [
239
+ {
240
+ "id": "h15",
241
+ "text": "schema_version is written on every save and checked on load; an unknown or newer version fails closed with a clear error rather than corrupting state",
242
+ "status": "confirmed"
243
+ }
244
+ ],
245
+ "hard_questions": [],
246
+ "links": []
247
+ }
248
+ ],
249
+ "open_vagueness": [
250
+ {
251
+ "id": "v1",
252
+ "text": "Whether to also publish a formal machine-readable JSON Schema file alongside the prose contract doc + dataclasses, or treat the dataclasses as the schema of record",
253
+ "kind": "follow_up",
254
+ "claim_id": null
255
+ },
256
+ {
257
+ "id": "v2",
258
+ "text": "Whether requirement-type claims should eventually carry acceptance criteria like plan tasks do (overlaps the spec-to-plan leg), or stay prose-only in the frame",
259
+ "kind": "follow_up",
260
+ "claim_id": null
261
+ }
262
+ ]
263
+ }