aw-spec-cli 0.1.21 → 0.1.23
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/assets/.appweaver/STACK-PROFILES.md +87 -8
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +47 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +41 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +62 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +18 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +4 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +115 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +5 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +225 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +3 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +104 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +159 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +153 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +203 -212
- package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +191 -224
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
- package/assets/.appweaver/scripts/python/aw-crstate.py +127 -2
- package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +17 -1
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +84 -4
- package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
- package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +6 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
- package/assets/.appweaver/stack-profiles/angular.json +26 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +38 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +19 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
- package/assets/.appweaver/stack-profiles/node-express.json +26 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +15 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
- package/assets/.appweaver/templates/ui-model-template.md +67 -0
- package/assets/.appweaver/templates/workflow-model-template.md +62 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +3 -3
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +5 -123
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +784 -0
- package/assets/foundations/java/Hexagonal/pack-foundation.sh +357 -0
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +399 -0
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +44 -0
- package/package.json +1 -1
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# unpack-foundation.sh — Java foundation unpacker for AW-Spec
|
|
4
|
+
#
|
|
5
|
+
# Unpacks an AW-Spec Java foundation pack into a target application,
|
|
6
|
+
# replacing the Java package sentinel with the target application package.
|
|
7
|
+
#
|
|
8
|
+
# Java foundation contract:
|
|
9
|
+
# Sentinel: io.appweaver
|
|
10
|
+
#
|
|
11
|
+
# Example:
|
|
12
|
+
# ./unpack-foundation.sh \
|
|
13
|
+
# --pack-file ./Hexagonal.pack.txt \
|
|
14
|
+
# --target-app-name FlightBooking \
|
|
15
|
+
# --out-dir backend
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# ----------------------------------------------------------- defaults --------------
|
|
21
|
+
|
|
22
|
+
PACK_FILE=''
|
|
23
|
+
TARGET_APP_NAME=''
|
|
24
|
+
OUT_DIR='src'
|
|
25
|
+
SENTINEL=''
|
|
26
|
+
FORCE=0
|
|
27
|
+
DRYRUN=0
|
|
28
|
+
|
|
29
|
+
# ----------------------------------------------------------- usage ----------------
|
|
30
|
+
|
|
31
|
+
usage() {
|
|
32
|
+
cat <<'EOF'
|
|
33
|
+
Usage:
|
|
34
|
+
unpack-foundation.sh \
|
|
35
|
+
--pack-file <pack-file> \
|
|
36
|
+
--target-app-name <app-name> \
|
|
37
|
+
--out-dir <output-dir> \
|
|
38
|
+
[--sentinel <sentinel>] \
|
|
39
|
+
[--force] \
|
|
40
|
+
[--dry-run]
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--pack-file Foundation pack file.
|
|
44
|
+
--target-app-name Target application name.
|
|
45
|
+
--out-dir Output directory.
|
|
46
|
+
--sentinel Optional sentinel override.
|
|
47
|
+
--force Allow existing destination files to be overwritten.
|
|
48
|
+
--dry-run Show what would be written without changing files.
|
|
49
|
+
-h, --help Show this help.
|
|
50
|
+
EOF
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# ----------------------------------------------------------- error -----------------
|
|
54
|
+
|
|
55
|
+
error() {
|
|
56
|
+
echo "Error: $*" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# ----------------------------------------------------------- arguments ------------
|
|
61
|
+
|
|
62
|
+
while [ "$#" -gt 0 ]; do
|
|
63
|
+
case "$1" in
|
|
64
|
+
--pack-file)
|
|
65
|
+
[ "$#" -ge 2 ] || error "--pack-file requires a value"
|
|
66
|
+
PACK_FILE="$2"
|
|
67
|
+
shift 2
|
|
68
|
+
;;
|
|
69
|
+
|
|
70
|
+
--target-app-name)
|
|
71
|
+
[ "$#" -ge 2 ] || error "--target-app-name requires a value"
|
|
72
|
+
TARGET_APP_NAME="$2"
|
|
73
|
+
shift 2
|
|
74
|
+
;;
|
|
75
|
+
|
|
76
|
+
--out-dir)
|
|
77
|
+
[ "$#" -ge 2 ] || error "--out-dir requires a value"
|
|
78
|
+
OUT_DIR="$2"
|
|
79
|
+
shift 2
|
|
80
|
+
;;
|
|
81
|
+
|
|
82
|
+
--sentinel)
|
|
83
|
+
[ "$#" -ge 2 ] || error "--sentinel requires a value"
|
|
84
|
+
SENTINEL="$2"
|
|
85
|
+
shift 2
|
|
86
|
+
;;
|
|
87
|
+
|
|
88
|
+
--force)
|
|
89
|
+
FORCE=1
|
|
90
|
+
shift
|
|
91
|
+
;;
|
|
92
|
+
|
|
93
|
+
--dry-run)
|
|
94
|
+
DRYRUN=1
|
|
95
|
+
shift
|
|
96
|
+
;;
|
|
97
|
+
|
|
98
|
+
-h|--help)
|
|
99
|
+
usage
|
|
100
|
+
exit 0
|
|
101
|
+
;;
|
|
102
|
+
|
|
103
|
+
*)
|
|
104
|
+
error "Unknown argument: $1"
|
|
105
|
+
;;
|
|
106
|
+
esac
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
# ----------------------------------------------------------- validate args ----------
|
|
110
|
+
|
|
111
|
+
[ -n "$PACK_FILE" ] || error "--pack-file is required"
|
|
112
|
+
[ -n "$TARGET_APP_NAME" ] || error "--target-app-name is required"
|
|
113
|
+
|
|
114
|
+
[ -f "$PACK_FILE" ] || error "Pack file not found: $PACK_FILE"
|
|
115
|
+
|
|
116
|
+
case "$TARGET_APP_NAME" in
|
|
117
|
+
*[!A-Za-z0-9._-]*)
|
|
118
|
+
error "Invalid application name '$TARGET_APP_NAME'. Allowed characters: A-Z a-z 0-9 . _ -"
|
|
119
|
+
;;
|
|
120
|
+
esac
|
|
121
|
+
|
|
122
|
+
# ----------------------------------------------------------- read pack metadata ----
|
|
123
|
+
|
|
124
|
+
PACK_SENTINEL=''
|
|
125
|
+
|
|
126
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
127
|
+
line="${line%$'\r'}"
|
|
128
|
+
|
|
129
|
+
case "$line" in
|
|
130
|
+
'# sentinel: '*)
|
|
131
|
+
PACK_SENTINEL="${line#'# sentinel: '}"
|
|
132
|
+
break
|
|
133
|
+
;;
|
|
134
|
+
esac
|
|
135
|
+
done < "$PACK_FILE"
|
|
136
|
+
|
|
137
|
+
if [ -n "$SENTINEL" ]; then
|
|
138
|
+
:
|
|
139
|
+
elif [ -n "$PACK_SENTINEL" ]; then
|
|
140
|
+
SENTINEL="$PACK_SENTINEL"
|
|
141
|
+
else
|
|
142
|
+
error "Could not determine sentinel from pack. Use --sentinel."
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
[ -n "$SENTINEL" ] || error "Sentinel cannot be empty"
|
|
146
|
+
|
|
147
|
+
# ----------------------------------------------------------- Java replacement -------
|
|
148
|
+
|
|
149
|
+
#
|
|
150
|
+
# Java package rules:
|
|
151
|
+
#
|
|
152
|
+
# io.appweaver
|
|
153
|
+
# ->
|
|
154
|
+
# <lowercase application name>
|
|
155
|
+
#
|
|
156
|
+
# io/appweaver
|
|
157
|
+
# ->
|
|
158
|
+
# <lowercase application name>
|
|
159
|
+
#
|
|
160
|
+
# The application directory itself keeps the original user-provided
|
|
161
|
+
# application name/casing.
|
|
162
|
+
#
|
|
163
|
+
|
|
164
|
+
TARGET_PACKAGE="$(printf '%s' "$TARGET_APP_NAME" | tr '[:upper:]' '[:lower:]')"
|
|
165
|
+
|
|
166
|
+
S_DOT="$SENTINEL"
|
|
167
|
+
T_DOT="$TARGET_PACKAGE"
|
|
168
|
+
|
|
169
|
+
S_PATH="$(printf '%s' "$SENTINEL" | tr '.' '/')"
|
|
170
|
+
T_PATH="$TARGET_PACKAGE"
|
|
171
|
+
|
|
172
|
+
FROM=()
|
|
173
|
+
TO=()
|
|
174
|
+
|
|
175
|
+
add_form() {
|
|
176
|
+
FROM+=("$1")
|
|
177
|
+
TO+=("$2")
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
add_form "$S_DOT" "$T_DOT"
|
|
181
|
+
add_form "$S_PATH" "$T_PATH"
|
|
182
|
+
|
|
183
|
+
# ----------------------------------------------------------- replacement ------------
|
|
184
|
+
|
|
185
|
+
#
|
|
186
|
+
# Apply replacements from longest source string to shortest.
|
|
187
|
+
# This avoids partial replacement problems when one replacement
|
|
188
|
+
# string is a prefix of another.
|
|
189
|
+
#
|
|
190
|
+
|
|
191
|
+
apply_repl() {
|
|
192
|
+
local input="$1"
|
|
193
|
+
local i
|
|
194
|
+
local from
|
|
195
|
+
local to
|
|
196
|
+
|
|
197
|
+
REPL_OUT="$input"
|
|
198
|
+
|
|
199
|
+
for i in "${!FROM[@]}"; do
|
|
200
|
+
from="${FROM[$i]}"
|
|
201
|
+
to="${TO[$i]}"
|
|
202
|
+
|
|
203
|
+
REPL_OUT="${REPL_OUT//$from/$to}"
|
|
204
|
+
done
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# ----------------------------------------------------------- output root ------------
|
|
208
|
+
|
|
209
|
+
if [ "$OUT_DIR" = "." ]; then
|
|
210
|
+
OUT_ROOT="$TARGET_APP_NAME"
|
|
211
|
+
else
|
|
212
|
+
OUT_ROOT="$OUT_DIR/$TARGET_APP_NAME"
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# ----------------------------------------------------------- parse pack blocks -------
|
|
216
|
+
|
|
217
|
+
rels=()
|
|
218
|
+
encs=()
|
|
219
|
+
contents=()
|
|
220
|
+
dir_rels=()
|
|
221
|
+
|
|
222
|
+
in_block=0
|
|
223
|
+
cur_rel=''
|
|
224
|
+
cur_enc=''
|
|
225
|
+
cur_content=''
|
|
226
|
+
first_line=1
|
|
227
|
+
|
|
228
|
+
file_re='^<<<FILE path="([^"]+)"( encoding="([^"]+)")?>>>[[:space:]]*$'
|
|
229
|
+
dir_re='^<<<DIR path="([^"]+)">>>[[:space:]]*$'
|
|
230
|
+
|
|
231
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
232
|
+
line="${line%$'\r'}"
|
|
233
|
+
|
|
234
|
+
if [ "$in_block" -eq 0 ]; then
|
|
235
|
+
|
|
236
|
+
if [[ "$line" =~ $file_re ]]; then
|
|
237
|
+
cur_rel="${BASH_REMATCH[1]}"
|
|
238
|
+
cur_enc="${BASH_REMATCH[3]:-}"
|
|
239
|
+
in_block=1
|
|
240
|
+
first_line=1
|
|
241
|
+
cur_content=''
|
|
242
|
+
|
|
243
|
+
elif [[ "$line" =~ $dir_re ]]; then
|
|
244
|
+
dir_rels+=("${BASH_REMATCH[1]}")
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
else
|
|
248
|
+
|
|
249
|
+
if [ "$line" = '<<<ENDFILE>>>' ]; then
|
|
250
|
+
rels+=("$cur_rel")
|
|
251
|
+
encs+=("$cur_enc")
|
|
252
|
+
contents+=("$cur_content")
|
|
253
|
+
|
|
254
|
+
in_block=0
|
|
255
|
+
|
|
256
|
+
elif [ "$first_line" -eq 1 ]; then
|
|
257
|
+
cur_content="$line"
|
|
258
|
+
first_line=0
|
|
259
|
+
|
|
260
|
+
else
|
|
261
|
+
cur_content="$cur_content"$'\n'"$line"
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
done < "$PACK_FILE"
|
|
267
|
+
|
|
268
|
+
[ "${#rels[@]}" -gt 0 ] || {
|
|
269
|
+
echo "Error: No <<<FILE>>> blocks found in pack: $PACK_FILE" >&2
|
|
270
|
+
exit 1
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# ----------------------------------------------------------- resolve directories ----
|
|
274
|
+
|
|
275
|
+
is_empty_java_package_parent() {
|
|
276
|
+
local rel="$1"
|
|
277
|
+
|
|
278
|
+
case "$rel" in
|
|
279
|
+
src/main/java/io|src/test/java/io)
|
|
280
|
+
return 0
|
|
281
|
+
;;
|
|
282
|
+
*)
|
|
283
|
+
return 1
|
|
284
|
+
;;
|
|
285
|
+
esac
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
dir_dests=()
|
|
289
|
+
|
|
290
|
+
for rel in "${dir_rels[@]}"; do
|
|
291
|
+
if is_empty_java_package_parent "$rel"; then
|
|
292
|
+
continue
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
apply_repl "$rel"
|
|
296
|
+
dir_dests+=("$OUT_ROOT/$REPL_OUT")
|
|
297
|
+
done
|
|
298
|
+
|
|
299
|
+
# ----------------------------------------------------------- resolve files ----------
|
|
300
|
+
|
|
301
|
+
dests=()
|
|
302
|
+
|
|
303
|
+
for rel in "${rels[@]}"; do
|
|
304
|
+
apply_repl "$rel"
|
|
305
|
+
dests+=("$OUT_ROOT/$REPL_OUT")
|
|
306
|
+
done
|
|
307
|
+
|
|
308
|
+
# ----------------------------------------------------------- conflict guard ----------
|
|
309
|
+
|
|
310
|
+
if [ "$FORCE" -eq 0 ] && [ "$DRYRUN" -eq 0 ]; then
|
|
311
|
+
|
|
312
|
+
for dest in "${dests[@]}"; do
|
|
313
|
+
if [ -e "$dest" ]; then
|
|
314
|
+
error "Destination already exists: $dest (use --force to overwrite)"
|
|
315
|
+
fi
|
|
316
|
+
done
|
|
317
|
+
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
# ----------------------------------------------------------- base64 decoder ----------
|
|
321
|
+
|
|
322
|
+
decode_base64() {
|
|
323
|
+
if base64 --help 2>&1 | grep -q -- '--decode'; then
|
|
324
|
+
base64 --decode
|
|
325
|
+
else
|
|
326
|
+
base64 -D
|
|
327
|
+
fi
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# ----------------------------------------------------------- create directories -------
|
|
331
|
+
|
|
332
|
+
directories_created=0
|
|
333
|
+
|
|
334
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
335
|
+
|
|
336
|
+
for dest in "${dir_dests[@]}"; do
|
|
337
|
+
echo "WOULD CREATE DIRECTORY $dest"
|
|
338
|
+
done
|
|
339
|
+
|
|
340
|
+
else
|
|
341
|
+
|
|
342
|
+
for dest in "${dir_dests[@]}"; do
|
|
343
|
+
mkdir -p "$dest"
|
|
344
|
+
directories_created=$((directories_created + 1))
|
|
345
|
+
done
|
|
346
|
+
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
# ----------------------------------------------------------- write files -------------
|
|
350
|
+
|
|
351
|
+
written=0
|
|
352
|
+
|
|
353
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
354
|
+
|
|
355
|
+
for i in "${!rels[@]}"; do
|
|
356
|
+
echo "WOULD WRITE ${dests[$i]}"
|
|
357
|
+
done
|
|
358
|
+
|
|
359
|
+
else
|
|
360
|
+
|
|
361
|
+
for i in "${!rels[@]}"; do
|
|
362
|
+
|
|
363
|
+
dest="${dests[$i]}"
|
|
364
|
+
enc="${encs[$i]}"
|
|
365
|
+
content="${contents[$i]}"
|
|
366
|
+
|
|
367
|
+
mkdir -p "$(dirname "$dest")"
|
|
368
|
+
|
|
369
|
+
if [ "$enc" = "base64" ]; then
|
|
370
|
+
printf '%s' "$content" | decode_base64 > "$dest"
|
|
371
|
+
else
|
|
372
|
+
apply_repl "$content"
|
|
373
|
+
printf '%s\n' "$REPL_OUT" > "$dest"
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
written=$((written + 1))
|
|
377
|
+
|
|
378
|
+
done
|
|
379
|
+
|
|
380
|
+
fi
|
|
381
|
+
|
|
382
|
+
# ----------------------------------------------------------- summary -----------------
|
|
383
|
+
|
|
384
|
+
echo
|
|
385
|
+
|
|
386
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
387
|
+
|
|
388
|
+
echo "DryRun: ${#rels[@]} file(s) and ${#dir_rels[@]} directorie(s) would be written to:"
|
|
389
|
+
echo " $OUT_ROOT"
|
|
390
|
+
|
|
391
|
+
else
|
|
392
|
+
|
|
393
|
+
echo "Unpacked $written file(s) and $directories_created directorie(s) to:"
|
|
394
|
+
echo " $OUT_ROOT"
|
|
395
|
+
|
|
396
|
+
fi
|
|
397
|
+
|
|
398
|
+
echo " Sentinel: $SENTINEL"
|
|
399
|
+
echo " Package: $TARGET_PACKAGE"
|
|
@@ -50,6 +50,50 @@ The auditing interfaces are the ones most often reported missing: they are in a
|
|
|
50
50
|
package from the aggregate types, so a project that references `AppWeaver.DomainAbstraction`
|
|
51
51
|
alone cannot see `IAggregateChild` at all. A rule that requires one requires its package.
|
|
52
52
|
|
|
53
|
+
## The other direction — framework types that shadow DOMAIN names
|
|
54
|
+
|
|
55
|
+
The map above is about a framework type the code cannot find. The opposite failure is a
|
|
56
|
+
framework type it finds *too easily*: a domain noun that the ambient scope already defines.
|
|
57
|
+
|
|
58
|
+
`Microsoft.NET.Sdk.Web` turns on implicit usings, so `System`, `System.Collections.Generic`,
|
|
59
|
+
`System.IO`, `System.Threading.Tasks`, `Microsoft.AspNetCore.Http` and
|
|
60
|
+
`Microsoft.AspNetCore.Routing` are in scope in **every** file without appearing in any
|
|
61
|
+
`using` line. A domain type sharing a name with one of theirs — `Route`, `Task`, `Activity`,
|
|
62
|
+
`Path`, `File`, `Timer`, `Index`, `Range`, `Version`, `Results`, `Endpoint`, `Environment`,
|
|
63
|
+
`Stream`, `Type`, `Queue`, `Stack` — is then an **ambiguous reference, CS0104**:
|
|
64
|
+
|
|
65
|
+
```csharp
|
|
66
|
+
using Acme.Clinic.Service.Care.Domain; // brings in the domain Route
|
|
67
|
+
|
|
68
|
+
public static Route? Route(string? value) // CS0104: Care.Domain.Route
|
|
69
|
+
// vs Microsoft.AspNetCore.Routing.Route
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The conflict is invisible in the file. Nothing in it names `Microsoft.AspNetCore.Routing`,
|
|
73
|
+
so the bare name reads as correct and fails only at build.
|
|
74
|
+
|
|
75
|
+
**The domain name is not the problem and never changes.** It is the ubiquitous language,
|
|
76
|
+
the plan spells it, and the code spells it back verbatim. What changes is how it is
|
|
77
|
+
written at the use site:
|
|
78
|
+
|
|
79
|
+
```csharp
|
|
80
|
+
public static Domain.Route? Route(string? value) =>
|
|
81
|
+
string.IsNullOrWhiteSpace(value) ? null : Domain.Route.From(value);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- **Qualify with the type's own enclosing namespace segment** — `Domain.Route` — at every
|
|
85
|
+
site the type is named: declarations, parameters, return types, generic arguments and
|
|
86
|
+
`<see cref="…"/>` comments.
|
|
87
|
+
- **Not a `using` alias and not the full namespace path.** One convention, so two features
|
|
88
|
+
never disambiguate the same name two ways.
|
|
89
|
+
- **Never rename the domain type** to avoid the clash, and never drop the domain type in
|
|
90
|
+
favour of the framework one.
|
|
91
|
+
|
|
92
|
+
`/aw-spec-implement` is told which of *this* plan's element names are affected before it
|
|
93
|
+
writes anything — the list comes from the lane's stack profile (`reserved_names` in
|
|
94
|
+
`.appweaver/stack-profiles/<id>.json`), so it is the same answer on every run rather than
|
|
95
|
+
something each pass has to notice for itself.
|
|
96
|
+
|
|
53
97
|
## Rules
|
|
54
98
|
|
|
55
99
|
- **Cite a framework type with its namespace** in plans and generated code, and add the
|
package/package.json
CHANGED