aw-spec-cli 0.1.15 → 0.1.16
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/orchestrator/modules/spec-state-gate.orch.yaml +87 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +83 -19
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +88 -19
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +131 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +126 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan-ui.orch.yaml +28 -25
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +48 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +97 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-story-plan.orch.yaml +216 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-sync-stories.orch.yaml +108 -27
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +515 -30
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +504 -28
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +158 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +205 -48
- package/assets/.appweaver/templates/story-template.md +37 -6
- package/package.json +1 -1
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
# Spec-anchored pipeline, spec phase. The spec is the CONTRACT and a story is an
|
|
5
5
|
# execution SLICE over it. The two directions between them each have their own
|
|
6
6
|
# workflow and neither is shared: sync-stories carries the SPEC forward into the
|
|
7
|
-
# backlog; /appweaver
|
|
7
|
+
# backlog; /appweaver sync-spec (⌛ not yet built — .appweaver/SPEC-EDIT-PROTOCOL.md is the
|
|
8
|
+
# hand route meanwhile) folds a hand-edited STORY back into the contract.
|
|
8
9
|
# Keeping them apart is what stops the spec->story rule having two implementations.
|
|
9
10
|
#
|
|
10
11
|
# WHAT THIS READS. The spec's `## Change History` — the version ledger. Each row names
|
|
@@ -110,7 +111,7 @@
|
|
|
110
111
|
# =============================================================================
|
|
111
112
|
|
|
112
113
|
name: aw-spec-sync-stories
|
|
113
|
-
description: "Raise and refresh the story backlog of the ACTIVE feature from its spec. Reads the spec's Change History ledger to find the requirements that have moved since the backlog was last in step, groups them into execution slices, asks before disturbing a story someone already has open, and writes one story per slice — creating, updating in place, or minting a follow-on where a story plan already exists. Slicing is steered by an opening strategy word: `single-run` puts the whole work set into ONE story, splitting it along its dependencies only where that story could not be picked up as one piece, and reporting the split either way; omitted, the number of slices is decided from the requirements. The grouping declares which slices stand behind which, and the kit computes DELIVERY WAVES from those edges — wave N holds the stories whose every dependency sits below it, so stories sharing a wave have no ordering between them and may be picked up in parallel. Writes `depends_on:` and `wave:` into each story's frontmatter, breaks any declared cycle deterministically, and regenerates the spec's Story Coverage block. Writes no requirements — /appweaver specify and /appweaver
|
|
114
|
+
description: "Raise and refresh the story backlog of the ACTIVE feature from its spec. Reads the spec's Change History ledger to find the requirements that have moved since the backlog was last in step, groups them into execution slices, asks before disturbing a story someone already has open, and writes one story per slice — creating, updating in place, or minting a follow-on where a story plan already exists. Slicing is steered by an opening strategy word: `single-run` puts the whole work set into ONE story, splitting it along its dependencies only where that story could not be picked up as one piece, and reporting the split either way; omitted, the number of slices is decided from the requirements. The grouping declares which slices stand behind which, and the kit computes DELIVERY WAVES from those edges — wave N holds the stories whose every dependency sits below it, so stories sharing a wave have no ordering between them and may be picked up in parallel. Writes `depends_on:` and `wave:` into each story's frontmatter, breaks any declared cycle deterministically, and regenerates the spec's Story Coverage block. Writes no requirements — /appweaver specify and /appweaver sync-spec own the contract."
|
|
114
115
|
version: 1.1.0
|
|
115
116
|
agent_agnostic: true
|
|
116
117
|
dialect: aw-spec.orchestrator/v1
|
|
@@ -342,6 +343,19 @@ workflow:
|
|
|
342
343
|
for what the LAST row named and leave the hand edit unnamed and unreconciled.
|
|
343
344
|
Resolve the state above, then re-run. (State: {{ledger_state}}.)
|
|
344
345
|
|
|
346
|
+
# 3a. THE TWO STATES THAT PASS `ok` AND SHOULD NOT PASS HERE. spec-check's decisive branch
|
|
347
|
+
# asks only whether a version ROW sits above the version the kit last recorded, and
|
|
348
|
+
# never opens the body — so `ledgered_edit` and `header_behind` are ok:true with a
|
|
349
|
+
# document nobody has re-baselined, and every LATER edit lands inside that same window
|
|
350
|
+
# and passes the same test. Syncing from there raises a backlog from rows that are
|
|
351
|
+
# recorded and a body that is not. The module is shared with plan, plan-ui,
|
|
352
|
+
# analyze-design, story-plan, analyze-slice and both implements — the fence is the
|
|
353
|
+
# same wherever spec.md is read and not stamped.
|
|
354
|
+
- id: spec_state_guard
|
|
355
|
+
action: include
|
|
356
|
+
module: .appweaver/orchestrator/modules/spec-state-gate.orch.yaml
|
|
357
|
+
with: { command: "/appweaver sync-stories" }
|
|
358
|
+
|
|
345
359
|
# 4. THE WORK SET. See the header for why it spans versions rather than reading the
|
|
346
360
|
# newest row alone, and for the v1.0 case.
|
|
347
361
|
- id: ledger_read
|
|
@@ -363,6 +377,9 @@ workflow:
|
|
|
363
377
|
- { name: synced_floor, from: "$.synced_floor" }
|
|
364
378
|
- { name: floor_source, from: "$.floor_source" }
|
|
365
379
|
- { name: latest_version, from: "$.latest_version" }
|
|
380
|
+
- { name: non_story_csv, from: "$.non_story_csv" }
|
|
381
|
+
- { name: non_story_any, from: "$.non_story_any" }
|
|
382
|
+
- { name: work_kind, from: "$.work_kind" }
|
|
366
383
|
|
|
367
384
|
# 4a. AN EMPTY LEDGER STOPS THE RUN. The table is there and carries no version row, which
|
|
368
385
|
# means the spec has never been versioned. There is no "since" to sync from, and
|
|
@@ -382,17 +399,48 @@ workflow:
|
|
|
382
399
|
/appweaver sync-stories. (If the spec was written by hand, add a row naming the
|
|
383
400
|
requirement ids it introduced and re-run spec-stamp.)
|
|
384
401
|
|
|
402
|
+
# 4a-bis. WHAT MOVED THAT NO STORY CAN BE RAISED FOR. Constraints and success criteria
|
|
403
|
+
# travel in the same version rows as requirements, and this workflow can act on
|
|
404
|
+
# neither: a story's `exercises:` is FR-/BR- only, because those are DELIVERED, while a
|
|
405
|
+
# CN-/DC-/IC-/UX- is MET and an SC- is SCORED. Until now that meant a row naming only
|
|
406
|
+
# those produced an empty work set and a run that stopped with "the backlog is already
|
|
407
|
+
# in step" — about the exact ids story-plan-check had just reported as stale.
|
|
408
|
+
#
|
|
409
|
+
# BEFORE the work gate and INDEPENDENT of it, on purpose. A row naming FR-001 AND
|
|
410
|
+
# CN-001 has real story work, so the gate below passes and the run continues — and
|
|
411
|
+
# branching this notice on "no work" would then have said nothing at all about the
|
|
412
|
+
# constraint, which is the same silence one case over. It fires on the ids, never on
|
|
413
|
+
# the shape of the run.
|
|
414
|
+
- id: non_story_notice
|
|
415
|
+
condition: "{{non_story_csv}} != ''"
|
|
416
|
+
action: verify_context
|
|
417
|
+
require_value: non_story_csv
|
|
418
|
+
equals: ""
|
|
419
|
+
on_mismatch: continue
|
|
420
|
+
on_mismatch_message: >
|
|
421
|
+
ALSO MOVED, AND NOT SLICEABLE: {{non_story_csv}}. These are carried by stories, not
|
|
422
|
+
delivered by them, so this run raises nothing for them and none of the writes below
|
|
423
|
+
touches them.
|
|
424
|
+
• CN-/DC-/IC-/UX- are BOUNDS. Every open story is built to satisfy the feature's whole
|
|
425
|
+
constraint set, so a moved bound touches all of them: re-run /appweaver story-plan on
|
|
426
|
+
each open story to design against the new wording, and see .appweaver/SPEC-EDIT-PROTOCOL.md
|
|
427
|
+
§4.2 for the by-hand reconciliation until /appweaver sync-spec ships.
|
|
428
|
+
• SC- are feature-level OUTCOMES, scored at /appweaver analyze-slice against the whole
|
|
429
|
+
feature — no story claims one, and none should.
|
|
430
|
+
|
|
385
431
|
# 4b. NOTHING TO DO IS NOT AN ERROR. Every version row is at or below the oldest open
|
|
386
432
|
# story's stamp: the backlog is already in step. Stopping here rather than running an
|
|
387
|
-
# empty grouping keeps the no-op cheap and the message honest.
|
|
433
|
+
# empty grouping keeps the no-op cheap and the message honest. Left as `work_any`
|
|
434
|
+
# (FR-/BR- only) deliberately — the non-story notice above has already fired by the
|
|
435
|
+
# time this is reached, so a constraint-only row now stops with its reason SAID.
|
|
388
436
|
- id: work_gate
|
|
389
437
|
action: verify_context
|
|
390
438
|
require_true: work_any
|
|
391
439
|
on_false: stop
|
|
392
440
|
on_false_message: >
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
441
|
+
No story work: every requirement a version row names has either been delivered by a
|
|
442
|
+
closed story or is already carried by an open one synced past it, so the backlog is in
|
|
443
|
+
step with {{spec_file}} at {{latest_version}}. Nothing was written. ({{work_note}}.)
|
|
396
444
|
|
|
397
445
|
# 4c. A REMOVED REQUIREMENT IS A DECISION, NOT A DEFAULT (E1). A row names what a version
|
|
398
446
|
# TOUCHED, and that includes ids it deleted. Those leave the work set — there is no
|
|
@@ -618,7 +666,8 @@ workflow:
|
|
|
618
666
|
on_mismatch_message: >
|
|
619
667
|
The grouping left these requirements out of every slice: {{unplaced_csv}}. No story
|
|
620
668
|
will be written for them by this run. Re-run /appweaver sync-stories to place them,
|
|
621
|
-
or raise them by hand
|
|
669
|
+
or raise them by hand from .appweaver/templates/story-template.md (/appweaver add-story,
|
|
670
|
+
which mints the id and stamps the frontmatter, is ⌛ not yet built).
|
|
622
671
|
|
|
623
672
|
- id: repeated_notice
|
|
624
673
|
condition: "{{repeated_csv}} != ''"
|
|
@@ -708,7 +757,8 @@ workflow:
|
|
|
708
757
|
the grouping produced no slice for any of them ({{work_count}} requirement(s) went
|
|
709
758
|
in, {{group_count}} group(s) came out). Nothing was declined and nothing was
|
|
710
759
|
written — re-run /appweaver sync-stories, and if it comes back empty again, raise
|
|
711
|
-
the stories by hand
|
|
760
|
+
the stories by hand from .appweaver/templates/story-template.md (/appweaver add-story
|
|
761
|
+
is ⌛ not yet built)
|
|
712
762
|
|
|
713
763
|
- id: nothing_declined
|
|
714
764
|
condition: "{{skipped_csv}} != ''"
|
|
@@ -828,7 +878,8 @@ workflow:
|
|
|
828
878
|
- THE SPEC IS THE CONTRACT AND THIS IS A SLICE OF WORK OVER IT. Nothing here
|
|
829
879
|
changes it. If writing this story exposes something the spec gets wrong or
|
|
830
880
|
leaves out, say so in Notes and leave the requirement alone — the contract
|
|
831
|
-
moves through /appweaver
|
|
881
|
+
moves through /appweaver sync-spec (⌛ not yet built — until it is, the hand
|
|
882
|
+
route is .appweaver/SPEC-EDIT-PROTOCOL.md), never through a story.
|
|
832
883
|
- Frontmatter: set `id:` to {{p.story}}, `exercises:` to exactly
|
|
833
884
|
[{{p.requirements_csv}}], `status: open`, and `spec_version:` to
|
|
834
885
|
{{latest_version}}. Give it a `title:` that names the OUTCOME a reviewer would
|
|
@@ -845,18 +896,19 @@ workflow:
|
|
|
845
896
|
- "## Requirements delivered": one line per id, saying what THIS story delivers
|
|
846
897
|
OF that requirement. A story rarely delivers a whole requirement; name the
|
|
847
898
|
part. Quote no requirement in full — the spec is the wording.
|
|
848
|
-
- "## Constraints"
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
from
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
899
|
+
- "## Constraints" — THE IDS ARE STAMPED FOR YOU; WRITE THE LINE EACH. The kit
|
|
900
|
+
lifts every CN-, DC-, IC- and UX- the spec declares into this story's
|
|
901
|
+
`constraints:` frontmatter, because they are declared aggregate-wide and so the
|
|
902
|
+
feature's whole set binds every slice of it. That field is the gate surface;
|
|
903
|
+
this section is what makes it READABLE. Write one line per id saying what THIS
|
|
904
|
+
slice has to do about it, and where one genuinely does not apply here, say so
|
|
905
|
+
plainly in its line — do not omit it. An omission used to be indistinguishable
|
|
906
|
+
from a bound nobody noticed, which is exactly how a slice gets built without one.
|
|
907
|
+
Carry the Experience Scope floors (device / browser / assistive technology) in
|
|
908
|
+
the same way wherever this slice has a UI surface: implement-ui authors from the
|
|
909
|
+
spec and the story, so a floor not stated here is one it will be built without.
|
|
910
|
+
Do NOT add these ids to `exercises:` — that field is FR-/BR- only, because it is
|
|
911
|
+
the delivery relation, and a constraint is not delivered, it is met.
|
|
860
912
|
- "## Acceptance": checkable statements in the spec's vocabulary, covering every
|
|
861
913
|
requirement in `exercises:` and every constraint listed above that this slice
|
|
862
914
|
can be observed to meet. These are what analyze-slice pairs tests against, so
|
|
@@ -966,11 +1018,11 @@ workflow:
|
|
|
966
1018
|
- WHERE AN ID IT ALREADY CITED HAS CHANGED WORDING, restate what this story
|
|
967
1019
|
delivers of it and re-check every acceptance line that depended on the old
|
|
968
1020
|
reading. That is the whole reason this story is being touched.
|
|
969
|
-
- "## Constraints"
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
these ids to `exercises:`.
|
|
1021
|
+
- "## Constraints" — the ids are re-stamped into `constraints:` for you from the
|
|
1022
|
+
spec as it now stands; this section's LINES are yours. A bound that has left the
|
|
1023
|
+
spec leaves this section; one that has arrived gets its line, with the acceptance
|
|
1024
|
+
line that shows it is met. Say plainly where one does not apply to this slice
|
|
1025
|
+
rather than dropping it. Never add these ids to `exercises:`.
|
|
974
1026
|
- NO IMPLEMENTATION DETAIL, and nothing here changes the spec. If the change
|
|
975
1027
|
reveals a problem with the contract, note it and leave the requirement alone.
|
|
976
1028
|
|
|
@@ -988,7 +1040,36 @@ workflow:
|
|
|
988
1040
|
# the sync sees one feature's spec, and an edge added by hand may name work outside
|
|
989
1041
|
# it. `--wave` is set outright — it is derived from the union, so re-deriving it is
|
|
990
1042
|
# the only way it stays true.
|
|
991
|
-
|
|
1043
|
+
# `--constraints` is a BARE FLAG: the op has the feature dir, so it lifts the ids
|
|
1044
|
+
# from spec.md itself. Nothing here enumerates them, because there is nothing to
|
|
1045
|
+
# decide — spec constraints are declared aggregate-wide ("must ALWAYS hold for the
|
|
1046
|
+
# aggregate, independent of any single operation"), so the feature's whole set binds
|
|
1047
|
+
# every slice of it. This is what makes `constraints:` a gate surface the KIT
|
|
1048
|
+
# writes; the body's "## Constraints" section keeps the per-slice prose and is
|
|
1049
|
+
# reconciled against the field, never overwritten by it.
|
|
1050
|
+
args: ["--feature-dir", "{{feature_dir}}", "--story", "{{p.story}}", "--ids", "{{p.requirements_csv}}", "--version", "{{latest_version}}", "--follows", "{{p.follows}}", "--title", "{{p.group_title}}", "--depends-on", "{{p.depends_on_csv}}", "--wave", "{{p.wave}}", "--constraints"]
|
|
1051
|
+
outputs:
|
|
1052
|
+
- { name: stamped_constraints_csv, from: "$.constraints_csv" }
|
|
1053
|
+
- { name: constraints_unlined_csv, from: "$.unlined_csv" }
|
|
1054
|
+
|
|
1055
|
+
# 10e. THE RECONCILE REPORT. The stamp owns the ID SET and the model owns the LINE
|
|
1056
|
+
# each id gets — "what this slice has to do about it" is the reason the section
|
|
1057
|
+
# is worth reading, and a script cannot write it. So a bound that is now in the
|
|
1058
|
+
# frontmatter with no line in the body is announced rather than silently added:
|
|
1059
|
+
# the gate surface is already closed by the field, and this is only so the
|
|
1060
|
+
# missing sentence is loud.
|
|
1061
|
+
- id: constraints_reconcile_notice
|
|
1062
|
+
condition: "{{constraints_unlined_csv}} != ''"
|
|
1063
|
+
action: verify_context
|
|
1064
|
+
require_value: constraints_unlined_csv
|
|
1065
|
+
equals: ""
|
|
1066
|
+
on_mismatch: continue
|
|
1067
|
+
on_mismatch_message: >
|
|
1068
|
+
{{p.story}} is bound by {{stamped_constraints_csv}} — the ids are stamped into its
|
|
1069
|
+
`constraints:` frontmatter, which is what implement, implement-ui and analyze-slice
|
|
1070
|
+
read. These have no line under "## Constraints" saying what this slice does about
|
|
1071
|
+
them: {{constraints_unlined_csv}}. Add one each, or say plainly that it does not
|
|
1072
|
+
apply here. The bound holds either way; what is missing is the reader's half.
|
|
992
1073
|
|
|
993
1074
|
# 11. THE RELATION, READ THE OTHER WAY ROUND. Every story declares what it delivers in
|
|
994
1075
|
# its own `exercises:`; the spec's Story Coverage block is that relation viewed from
|