aw-spec-cli 0.1.15 → 0.1.17

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 (69) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +18 -18
  2. package/assets/.appweaver/ORCH-DIALECT.md +1 -3
  3. package/assets/.appweaver/RULE-PARTITION.md +29 -13
  4. package/assets/.appweaver/STACK-PROFILES.md +10 -9
  5. package/assets/.appweaver/orchestrator/.state/smoke.state.json +32 -0
  6. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +4 -1
  7. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +251 -0
  8. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +104 -35
  9. package/assets/.appweaver/orchestrator/orchestrator.py +5 -4
  10. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +94 -36
  11. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +1 -1
  12. package/assets/.appweaver/orchestrator/rev-templates/domain-model-template.skeleton.md +115 -0
  13. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +2 -9
  14. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +16 -40
  15. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +38 -17
  16. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +8 -8
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +10 -11
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +673 -0
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +535 -0
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +643 -0
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +78 -626
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +7 -7
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +16 -14
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +2 -2
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +243 -144
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +882 -464
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -4
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +32 -91
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  31. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +832 -477
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +2 -2
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +132 -0
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +38 -5
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +3 -3
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +271 -892
  37. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +1096 -2911
  38. package/assets/.appweaver/scripts/bash/aw-xref.sh +1 -2
  39. package/assets/.appweaver/scripts/bash/common.sh +47 -0
  40. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +936 -2766
  41. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +1 -2
  42. package/assets/.appweaver/scripts/python/aw-payload-parity.py +174 -0
  43. package/assets/.appweaver/scripts/python/aw-stack.py +6 -2
  44. package/assets/.appweaver/scripts/python/aw-xref.py +185 -292
  45. package/assets/.appweaver/templates/constitution-ui-template.md +1 -1
  46. package/assets/.appweaver/templates/delta-design-template.md +120 -30
  47. package/assets/.appweaver/templates/delta-domain-model-template.md +81 -0
  48. package/assets/.appweaver/templates/delta-spec-template.md +43 -17
  49. package/assets/.appweaver/templates/design-template.md +68 -98
  50. package/assets/.appweaver/templates/domain-model-template.md +130 -0
  51. package/assets/.appweaver/templates/okf-concept-template.md +2 -2
  52. package/assets/.appweaver/templates/source-map-template.md +3 -3
  53. package/assets/.appweaver/templates/spec-template.md +100 -122
  54. package/assets/.appweaver/templates/ui-delta-design-template.md +159 -0
  55. package/assets/.appweaver/templates/ui-design-template.md +46 -75
  56. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +7 -18
  57. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +34 -39
  58. package/assets/guardrails/requirement-spec.txt +2 -2
  59. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  60. package/package.json +1 -1
  61. package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +0 -105
  62. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -251
  63. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -749
  64. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -253
  65. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +0 -540
  66. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan-ui.orch.yaml +0 -597
  67. package/assets/.appweaver/orchestrator/workflows/aw-spec-story-plan.orch.yaml +0 -945
  68. package/assets/.appweaver/orchestrator/workflows/aw-spec-sync-stories.orch.yaml +0 -1040
  69. package/assets/.appweaver/templates/story-template.md +0 -147
@@ -6,10 +6,9 @@
6
6
  #
7
7
  # aw-xref.ps1 record --using X --design <design.md> [--origin ...] [--date YYYY-MM-DD] [--root DIR]
8
8
  # aw-xref.ps1 list --aggregate Y [--root DIR] [--bundle knowledge]
9
- # aw-xref.ps1 concept-upsert --aggregate X [--source-files a,b,c] [--lane backend|frontend] [--merge] [--description D] [--origin ...] [--root DIR]
9
+ # aw-xref.ps1 concept-upsert --aggregate X [--source-files a,b,c] [--description D] [--origin ...] [--root DIR]
10
10
  # aw-xref.ps1 concept-overview --aggregate X (--text PROSE | --text-file F) [--root DIR]
11
11
  # aw-xref.ps1 concept-paths --aggregate X | --feature-dir <dir> [--root DIR] [--bundle knowledge]
12
- # aw-xref.ps1 concept-coverage --aggregate X | --feature-dir <dir> [--ids "FR-001,BR-002"] [--max-list N] [--root DIR] [--bundle knowledge]
13
12
  $ErrorActionPreference = "Stop"
14
13
  $core = Join-Path $PSScriptRoot "..\python\aw-xref.py"
15
14
  & python3 $core @args
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env python3
2
+ """aw-payload-parity.py — prove the two shells run the SAME python.
3
+
4
+ Most of aw-spec-actions is one python program embedded twice: as a `<<'PY'` heredoc in
5
+ aw-spec-actions.sh and as a `$PyName = @'…'@` here-string in aw-spec-actions.ps1. The
6
+ contract is that each pair is BYTE-IDENTICAL, and nothing checked it — so a fix applied to
7
+ one shell and forgotten in the other is a gate that behaves differently on Windows, in
8
+ silence. Three of the ops with no twin at all are on the forward chain (resolve-hooks, with
9
+ call sites in 21 of the workflows, and checklist-read / checklist-apply, which produce the
10
+ analyze phases' LIFT-FAILURE findings), and every one of them was read in bash when the
11
+ workflows were reviewed.
12
+
13
+ WHAT IT CHECKS
14
+ 1. Every bash payload has a byte-identical PowerShell twin.
15
+ 2. Every PowerShell payload has a byte-identical bash twin.
16
+ Payloads with no twin are listed, not counted against a hard-coded number: the split is
17
+ whatever the files say today, and pinning it would need editing on every legitimate change.
18
+
19
+ DUAL-AUTHORED BY DECISION. The ops in ACCEPTED_BASH_ONLY are bash-only on purpose (their
20
+ PowerShell path is written natively rather than shared) and are reported separately, so the
21
+ exit code reacts only to a NEW divergence. Moving one out of that list means it gained a
22
+ shared payload; adding one means the decision was taken to dual-author it — and either way
23
+ the reviewer has to say so in the same commit.
24
+
25
+ exit 0 every payload is paired, or unpaired only by accepted decision
26
+ exit 1 a new unpaired payload, or a pair that has drifted apart
27
+
28
+ Usage: aw-payload-parity.py [--root DIR] [--verbose]
29
+ """
30
+
31
+ import argparse
32
+ import hashlib
33
+ import os
34
+ import re
35
+ import sys
36
+
37
+ SH_REL = ".appweaver/scripts/bash/aw-spec-actions.sh"
38
+ PS_REL = ".appweaver/scripts/powershell/aw-spec-actions.ps1"
39
+
40
+ # Bash payloads with no shared PowerShell twin BY DECISION, not by oversight. Each is
41
+ # implemented natively on the PowerShell side and the two must be reviewed in pairs.
42
+ ACCEPTED_BASH_ONLY = {
43
+ "cmd_resolve_hooks",
44
+ "cmd_list_contexts",
45
+ "cmd_context_paths",
46
+ "cmd_list_features",
47
+ # The two change-listing ops. Both walk changes/<cr-id>/ and read a header line out of
48
+ # each delta document — directory enumeration and a regex, which PowerShell does
49
+ # natively without paying for a python spawn per invocation. Short enough to review as
50
+ # a pair, which is the bar for this list.
51
+ "cmd_cr_list",
52
+ "cmd_cr_paths",
53
+ # Aggregate overlap between open model deltas: two markdown regexes over a directory
54
+ # listing. Native on both sides for the same reason as the pair above.
55
+ "cmd_cr_overlap",
56
+ # Header stamping and wave discovery are a few lines of regex over a markdown header.
57
+ # PowerShell does that natively at a fraction of the cost of spawning python, and both
58
+ # sides are short enough to review as a pair — which is the bar for this list.
59
+ "_stamp_header",
60
+ "_max_open_wave",
61
+ "cmd_checklist_read",
62
+ "cmd_checklist_apply",
63
+ "cmd_compose_constitution",
64
+ "cmd_constitution_verify",
65
+ "cmd_component_verify",
66
+ "cmd_cr_archive",
67
+ "cmd_version_stamp",
68
+ }
69
+
70
+
71
+ def bash_payloads(text):
72
+ """[(owning function, payload, first line, last line)] in file order."""
73
+ out, owner, lines, i = [], "(top level)", text.split("\n"), 0
74
+ while i < len(lines):
75
+ m = re.match(r"^([A-Za-z_][A-Za-z0-9_]*)\(\)\s*\{", lines[i])
76
+ if m:
77
+ owner = m.group(1)
78
+ if re.search(r"<<'PY'\s*$", lines[i]):
79
+ j, body = i + 1, []
80
+ while j < len(lines) and lines[j] != "PY":
81
+ body.append(lines[j])
82
+ j += 1
83
+ out.append((owner, "\n".join(body), i + 2, j))
84
+ i = j
85
+ i += 1
86
+ return out
87
+
88
+
89
+ def ps_payloads(text):
90
+ """[(variable name, payload, first line, last line)] in file order."""
91
+ out, lines, i = [], text.split("\n"), 0
92
+ while i < len(lines):
93
+ m = re.match(r"^\$(Py[A-Za-z0-9_]*)\s*=\s*@'\s*$", lines[i])
94
+ if m:
95
+ j, body = i + 1, []
96
+ while j < len(lines) and lines[j] != "'@":
97
+ body.append(lines[j])
98
+ j += 1
99
+ out.append((m.group(1), "\n".join(body), i + 2, j))
100
+ i = j
101
+ i += 1
102
+ return out
103
+
104
+
105
+ def digest(s):
106
+ return hashlib.sha256(s.encode("utf-8")).hexdigest()
107
+
108
+
109
+ def main():
110
+ ap = argparse.ArgumentParser(description="check bash/PowerShell python-payload parity")
111
+ ap.add_argument("--root", default="", help="kit root (default: this script's kit)")
112
+ ap.add_argument("--verbose", action="store_true", help="list every matched pair too")
113
+ args = ap.parse_args()
114
+
115
+ root = args.root or os.path.normpath(
116
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", ".."))
117
+ sh_path, ps_path = os.path.join(root, SH_REL), os.path.join(root, PS_REL)
118
+ for p in (sh_path, ps_path):
119
+ if not os.path.isfile(p):
120
+ print("aw-payload-parity: not found: %s" % p, file=sys.stderr)
121
+ return 2
122
+
123
+ sh = bash_payloads(open(sh_path, encoding="utf-8").read())
124
+ ps = ps_payloads(open(ps_path, encoding="utf-8").read())
125
+
126
+ ps_by_hash = {}
127
+ for name, body, a, b in ps:
128
+ ps_by_hash.setdefault(digest(body), []).append((name, a, b))
129
+ sh_by_hash = {}
130
+ for owner, body, a, b in sh:
131
+ sh_by_hash.setdefault(digest(body), []).append((owner, a, b))
132
+
133
+ paired, accepted, unpaired_sh, unpaired_ps = [], [], [], []
134
+ for owner, body, a, b in sh:
135
+ twin = ps_by_hash.get(digest(body))
136
+ if twin:
137
+ paired.append((owner, twin[0][0]))
138
+ elif owner in ACCEPTED_BASH_ONLY:
139
+ accepted.append((owner, a, b))
140
+ else:
141
+ unpaired_sh.append((owner, a, b))
142
+ for name, body, a, b in ps:
143
+ if not sh_by_hash.get(digest(body)):
144
+ unpaired_ps.append((name, a, b))
145
+
146
+ print("payload parity: %d bash, %d powershell, %d byte-identical pair(s)"
147
+ % (len(sh), len(ps), len(paired)))
148
+ if args.verbose:
149
+ for owner, name in paired:
150
+ print(" ok %-34s == $%s" % (owner, name))
151
+ if accepted:
152
+ print("\ndual-authored by decision (%d) — PowerShell implements these natively, so a "
153
+ "change to one must be mirrored by hand:" % len(accepted))
154
+ for owner, a, b in accepted:
155
+ print(" -- %-34s %s:%d-%d" % (owner, os.path.basename(sh_path), a, b))
156
+
157
+ failed = bool(unpaired_sh or unpaired_ps)
158
+ if unpaired_sh:
159
+ print("\nFAIL — bash payloads with no byte-identical PowerShell twin:")
160
+ for owner, a, b in unpaired_sh:
161
+ print(" !! %-34s %s:%d-%d" % (owner, os.path.basename(sh_path), a, b))
162
+ if unpaired_ps:
163
+ print("\nFAIL — PowerShell payloads with no byte-identical bash twin:")
164
+ for name, a, b in unpaired_ps:
165
+ print(" !! $%-33s %s:%d-%d" % (name, os.path.basename(ps_path), a, b))
166
+ if failed:
167
+ print("\nA payload changed in one shell and not the other, or a new op shipped to one "
168
+ "shell only. Copy the payload verbatim into its twin — they are byte-identical "
169
+ "by contract — or, if the op is deliberately dual-authored, add its function to "
170
+ "ACCEPTED_BASH_ONLY in this file and say why in the commit.")
171
+ return 1 if failed else 0
172
+
173
+
174
+ sys.exit(main())
@@ -901,9 +901,13 @@ def cmd_resolve(args):
901
901
  # when implement writes into it. Every phase that READS the subtree — implement,
902
902
  # build, run, onboard — leaves the check on.
903
903
 
904
+ # Named in the "no <kind> lane is declared, and %s needs one" message, for a caller that
905
+ # passed --require but no --command of its own. `implement` covers both lanes in one
906
+ # command and requires neither kind, so it passes no --require at all and never reaches
907
+ # these.
904
908
  KIND_PHASES = {
905
- "backend": "implement / implement-delta / build / run",
906
- "frontend": "ui-implement / ui-implement-delta",
909
+ "backend": "implement's service lane / build / run",
910
+ "frontend": "implement's frontend lane",
907
911
  }
908
912
 
909
913