@workflow-cannon/workspace-kit 0.17.0 → 0.24.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 (144) hide show
  1. package/README.md +23 -9
  2. package/dist/cli/doctor-planning-issues.js +3 -22
  3. package/dist/cli/run-command.js +22 -38
  4. package/dist/cli.js +95 -4
  5. package/dist/contracts/command-manifest.d.ts +17 -0
  6. package/dist/contracts/command-manifest.js +1 -0
  7. package/dist/contracts/index.d.ts +1 -1
  8. package/dist/contracts/module-contract.d.ts +12 -11
  9. package/dist/core/agent-instruction-surface.d.ts +33 -0
  10. package/dist/core/agent-instruction-surface.js +46 -0
  11. package/dist/core/config-cli.js +13 -17
  12. package/dist/core/config-metadata.js +101 -2
  13. package/dist/core/index.d.ts +4 -1
  14. package/dist/core/index.js +3 -0
  15. package/dist/core/module-command-router.js +19 -1
  16. package/dist/core/module-registry-resolve.d.ts +27 -0
  17. package/dist/core/module-registry-resolve.js +91 -0
  18. package/dist/core/module-registry.d.ts +14 -0
  19. package/dist/core/module-registry.js +57 -0
  20. package/dist/core/planning/build-plan-session-file.d.ts +29 -0
  21. package/dist/core/planning/build-plan-session-file.js +58 -0
  22. package/dist/core/planning/index.d.ts +17 -0
  23. package/dist/core/planning/index.js +15 -0
  24. package/dist/core/policy.js +18 -8
  25. package/dist/core/state/unified-state-db.d.ts +21 -0
  26. package/dist/core/state/unified-state-db.js +80 -0
  27. package/dist/core/workspace-kit-config.js +13 -1
  28. package/dist/modules/agent-behavior/builtins.d.ts +3 -0
  29. package/dist/modules/agent-behavior/builtins.js +71 -0
  30. package/dist/modules/agent-behavior/explain.d.ts +6 -0
  31. package/dist/modules/agent-behavior/explain.js +46 -0
  32. package/dist/modules/agent-behavior/index.d.ts +4 -0
  33. package/dist/modules/agent-behavior/index.js +461 -0
  34. package/dist/modules/agent-behavior/interview-session-file.d.ts +9 -0
  35. package/dist/modules/agent-behavior/interview-session-file.js +43 -0
  36. package/dist/modules/agent-behavior/interview.d.ts +13 -0
  37. package/dist/modules/agent-behavior/interview.js +88 -0
  38. package/dist/modules/agent-behavior/persistence.d.ts +6 -0
  39. package/dist/modules/agent-behavior/persistence.js +89 -0
  40. package/dist/modules/agent-behavior/store.d.ts +34 -0
  41. package/dist/modules/agent-behavior/store.js +119 -0
  42. package/dist/modules/agent-behavior/types.d.ts +28 -0
  43. package/dist/modules/agent-behavior/types.js +1 -0
  44. package/dist/modules/agent-behavior/validate.d.ts +11 -0
  45. package/dist/modules/agent-behavior/validate.js +123 -0
  46. package/dist/modules/approvals/index.js +54 -51
  47. package/dist/modules/approvals/policy-sensitive-commands.d.ts +4 -0
  48. package/dist/modules/approvals/policy-sensitive-commands.js +4 -0
  49. package/dist/modules/approvals/review-runtime.js +1 -2
  50. package/dist/modules/documentation/index.js +47 -45
  51. package/dist/modules/documentation/normalizer.d.ts +3 -0
  52. package/dist/modules/documentation/normalizer.js +171 -0
  53. package/dist/modules/documentation/parser.d.ts +7 -0
  54. package/dist/modules/documentation/parser.js +39 -0
  55. package/dist/modules/documentation/policy-sensitive-commands.d.ts +5 -0
  56. package/dist/modules/documentation/policy-sensitive-commands.js +8 -0
  57. package/dist/modules/documentation/renderer.d.ts +23 -0
  58. package/dist/modules/documentation/renderer.js +105 -0
  59. package/dist/modules/documentation/runtime-batch.d.ts +10 -0
  60. package/dist/modules/documentation/runtime-batch.js +67 -0
  61. package/dist/modules/documentation/runtime-config.d.ts +11 -0
  62. package/dist/modules/documentation/runtime-config.js +54 -0
  63. package/dist/modules/documentation/runtime-render-support.d.ts +8 -0
  64. package/dist/modules/documentation/runtime-render-support.js +36 -0
  65. package/dist/modules/documentation/runtime.js +22 -510
  66. package/dist/modules/documentation/types.d.ts +182 -0
  67. package/dist/modules/documentation/validator.d.ts +8 -0
  68. package/dist/modules/documentation/validator.js +234 -0
  69. package/dist/modules/documentation/view-models.d.ts +3 -0
  70. package/dist/modules/documentation/view-models.js +124 -0
  71. package/dist/modules/improvement/generate-recommendations-runtime.js +3 -3
  72. package/dist/modules/improvement/improvement-state.d.ts +2 -2
  73. package/dist/modules/improvement/improvement-state.js +52 -23
  74. package/dist/modules/improvement/index.js +140 -138
  75. package/dist/modules/improvement/ingest.d.ts +1 -1
  76. package/dist/modules/improvement/policy-sensitive-commands.d.ts +4 -0
  77. package/dist/modules/improvement/policy-sensitive-commands.js +7 -0
  78. package/dist/modules/index.d.ts +6 -0
  79. package/dist/modules/index.js +17 -0
  80. package/dist/modules/planning/artifact.d.ts +19 -0
  81. package/dist/modules/planning/artifact.js +72 -0
  82. package/dist/modules/planning/index.js +605 -6
  83. package/dist/modules/planning/question-engine.d.ts +25 -0
  84. package/dist/modules/planning/question-engine.js +284 -0
  85. package/dist/modules/planning/types.d.ts +9 -0
  86. package/dist/modules/planning/types.js +39 -0
  87. package/dist/modules/task-engine/doctor-planning-persistence.js +21 -13
  88. package/dist/modules/task-engine/index.d.ts +1 -2
  89. package/dist/modules/task-engine/index.js +1 -1143
  90. package/dist/modules/task-engine/migrate-task-persistence-runtime.js +31 -4
  91. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.d.ts +2 -0
  92. package/dist/modules/task-engine/migrate-wishlist-intake-runtime.js +146 -0
  93. package/dist/modules/task-engine/planning-open.d.ts +2 -9
  94. package/dist/modules/task-engine/planning-open.js +4 -15
  95. package/dist/modules/task-engine/policy-sensitive-commands.d.ts +5 -0
  96. package/dist/modules/task-engine/policy-sensitive-commands.js +5 -0
  97. package/dist/modules/task-engine/sqlite-dual-planning.d.ts +11 -2
  98. package/dist/modules/task-engine/sqlite-dual-planning.js +134 -28
  99. package/dist/modules/task-engine/strict-task-validation.js +3 -0
  100. package/dist/modules/task-engine/suggestions.js +2 -1
  101. package/dist/modules/task-engine/task-engine-internal.d.ts +2 -0
  102. package/dist/modules/task-engine/task-engine-internal.js +1304 -0
  103. package/dist/modules/task-engine/task-type-validation.js +40 -0
  104. package/dist/modules/task-engine/wishlist-intake.d.ts +22 -0
  105. package/dist/modules/task-engine/wishlist-intake.js +180 -0
  106. package/dist/modules/task-engine/wishlist-validation.d.ts +4 -0
  107. package/dist/modules/task-engine/wishlist-validation.js +19 -0
  108. package/dist/modules/workspace-config/index.js +9 -11
  109. package/package.json +2 -2
  110. package/schemas/agent-behavior-profile.schema.json +52 -0
  111. package/schemas/task-engine-run-contracts.schema.json +80 -5
  112. package/src/modules/documentation/README.md +16 -25
  113. package/src/modules/documentation/RULES.md +9 -9
  114. package/src/modules/documentation/index.ts +54 -49
  115. package/src/modules/documentation/instructions/document-project.md +6 -6
  116. package/src/modules/documentation/instructions/generate-document.md +4 -4
  117. package/src/modules/documentation/normalizer.ts +187 -0
  118. package/src/modules/documentation/parser.ts +41 -0
  119. package/src/modules/documentation/policy-sensitive-commands.ts +8 -0
  120. package/src/modules/documentation/renderer.ts +121 -0
  121. package/src/modules/documentation/runtime-batch.ts +74 -0
  122. package/src/modules/documentation/runtime-config.ts +68 -0
  123. package/src/modules/documentation/runtime-render-support.ts +39 -0
  124. package/src/modules/documentation/runtime.ts +28 -600
  125. package/src/modules/documentation/schemas/documentation-schema.md +37 -54
  126. package/src/modules/documentation/types.ts +228 -0
  127. package/src/modules/documentation/validator.ts +247 -0
  128. package/src/modules/documentation/view-models.ts +132 -0
  129. package/src/modules/documentation/views/agents.view.yaml +18 -0
  130. package/src/modules/documentation/views/architecture.view.yaml +18 -0
  131. package/src/modules/documentation/views/principles.view.yaml +18 -0
  132. package/src/modules/documentation/views/readme.view.yaml +18 -0
  133. package/src/modules/documentation/views/releasing.view.yaml +18 -0
  134. package/src/modules/documentation/views/roadmap.view.yaml +18 -0
  135. package/src/modules/documentation/views/runbooks-consumer-cadence.view.yaml +18 -0
  136. package/src/modules/documentation/views/runbooks-parity-validation-flow.view.yaml +18 -0
  137. package/src/modules/documentation/views/runbooks-release-channels.view.yaml +18 -0
  138. package/src/modules/documentation/views/security.view.yaml +18 -0
  139. package/src/modules/documentation/views/support.view.yaml +18 -0
  140. package/src/modules/documentation/views/terms.view.yaml +18 -0
  141. package/src/modules/documentation/views/workbooks-phase2-config-policy-workbook.view.yaml +18 -0
  142. package/src/modules/documentation/views/workbooks-task-engine-workbook.view.yaml +18 -0
  143. package/src/modules/documentation/views/workbooks-transcript-automation-baseline.view.yaml +18 -0
  144. package/src/modules/documentation/state.md +0 -8
@@ -1,54 +1,37 @@
1
- meta|v=1|doc=<manifest|rules|runbook|workbook|map|workflows|commands|decisions|glossary|observed|planned|checks>|truth=<canonical|observed|planned>|st=<active|deprecated|draft>
2
-
3
- syntax|rec=one_per_line|sep=||kv==|list=,|seq=>|all=+|bool=true,false
4
- ids|rule=R[0-9]{3,}|wf=W[0-9]{3,}|cmd=C[0-9]{3,}|decision=D[0-9]{3,}|observed=O[0-9]{3,}|planned=P[0-9]{3,}|check=K[0-9]{3,}
5
- sem|lvl=must,must_not,should,may|risk=low,medium,high,critical|ap=none,prompt,required|act=auto,warn,prompt,stop
6
- author|meta_first_once=true|one_fact_per_record=true|exceptions_inline=true|no_vague_directives=true|observed_ne_rule=true|planned_ne_rule=true|stable_order=true
7
-
8
- project|name=<name>|type=<type>|scope=<scope>
9
- stack|<key=value>...
10
- prio|<p1>><p2>><p3>...
11
- truth|order=<t1>><t2>><t3>><t4>
12
- ref|name=<name>|path=<path>
13
-
14
- rule|<RID>|<lvl>|<scope>|<directive>|unless=<cond>|also=<list>|risk=<risk>|ap=<ap>|ov=<act>|st=<st>|refs=<list>
15
- path|<path>|role=<role>|has=<list>|xhas=<list>|deps=<list>|xdeps=<list>|check=<list>|st=<st>|refs=<list>
16
- module|<name>|role=<role>|owns=<list>|deps=<list>|xdeps=<list>|entry=<list>|tests=<list>|st=<st>|refs=<list>
17
-
18
- runbook|<name>|<scope>|<owner>
19
- workbook|<name>|<phase>|<status>
20
- intent|<fact_or_guidance>
21
- chain|<step>|<command>|expect_exit=<code>
22
- artifact|path=<path>|schema=<schema_path>
23
- state|name=<name>|dist_tag=<tag>|intent=<intent>
24
- transition|from=<from>|to=<to>|requires=<list>
25
- promotion|from=<from>|to=<to>|requires=<list>
26
- rollback|strategy=<strategy>|note=<note>
27
- command|name=<name>|purpose=<purpose>|sensitivity=<non_sensitive|policy_sensitive>
28
- config|key=<key>|default=<value>
29
- cadence|rule=<rule>
30
- guardrail|<GID>|<lvl>|<directive>|st=<st>
31
-
32
- wf|<WID>|name=<name>|when=<trigger>|do=<s1>><s2>><s3>|done=<d1>+<d2>|forbid=<list>|ask_if=<cond>|halt_if=<cond>|ap=<ap>|risk=<risk>|st=<st>|refs=<list>
33
- cmd|<CID>|name=<name>|use=<command>|scope=<scope>|expect=<result>|risk=<risk>|st=<st>
34
- decision|<DID>|topic=<topic>|choice=<choice>|why=<reason>|then=<consequence>|st=<st>|refs=<list>
35
- term|<name>|def=<definition>|st=<st>
36
-
37
- observed|<OID>|scope=<scope>|fact=<fact>|evidence=<evidence>|risk=<risk>|st=observed|refs=<list>
38
- planned|<PID>|scope=<scope>|target=<target>|why=<reason>|st=planned|refs=<list>
39
- check|<KID>|scope=<scope>|assert=<assertion>|when=<cond>|on_fail=<act>|st=<st>|refs=<list>
40
-
41
- order|manifest=meta,project,stack,prio,truth,ref
42
- order|rules=global,risky,scoped,workflow,style
43
- order|map=roots,major,special,legacy
44
- order|workflows=common,risky,edge,clarify
45
-
46
- defaults|omit_optional=true|omit_empty=true|lvl_explicit=true|scope_explicit=true|directive_explicit=true
47
- stop|critical_secret_risk=true|destructive_unapproved=true|policy_conflict_unresolved=true
48
- prompt|multi_valid_interpretations=true|required_approval_missing=true
49
- warn|should_violation=true|low_risk_uncertainty=true
50
-
51
- directive|good=add_migration,preserve_backward_compatibility,contain_business_logic,commit_secrets,manual_edit
52
- directive|bad=best_practices,clean_code,good_design,keep_it_simple,do_the_right_thing
53
- scope|good=repo,src/api,src/domain,public_api,schema_changes,behavior_change
54
- scope|bad=general,misc,various,important_stuff
1
+ meta|schema=base.v2|doc=<manifest|rules|runbook|workbook|map|workflows|commands|decisions|glossary|observed|planned|checks>|truth=<canonical|observed|planned>|status=<active|deprecated|draft>|profile=<core|runbook|workbook>
2
+
3
+ syntax|record=one_per_line|separator=||assignment==|list=,|sequence=>|conjunction=+|bool=true,false
4
+ ids|rule=R[0-9]{3,}|workflow=W[0-9]{3,}|command=C[0-9]{3,}|decision=D[0-9]{3,}|observed=O[0-9]{3,}|planned=P[0-9]{3,}|check=K[0-9]{3,}|example=E[0-9]{3,}|guardrail=G[0-9]{3,}
5
+ semantics|level=<must|must_not|should|may>|risk=<low|medium|high|critical>|approval=<none|prompt|required>|override=<auto|warn|prompt|stop>|refType=<adr|file|code|doc|issue|pr|test|external>
6
+ authoring|metaFirstOnce=true|oneFactPerRecord=true|exceptionsInline=true|noVagueDirectives=true|stableOrder=true
7
+
8
+ record|type=meta|required=schema,doc,truth,status|optional=profile,title,owner,tags,refs
9
+ record|type=ref|required=id,type,target|optional=label,note,status
10
+ record|type=rule|required=id,level,scope,directive,why|optional=unless,also,risk,approval,override,status,refs
11
+ record|type=check|required=id,scope,assertion|optional=when,onFail,status,refs
12
+ record|type=decision|required=id,topic,choice,why|optional=consequence,status,refs
13
+ record|type=example|required=id,for,kind,text|optional=status,refs
14
+ record|type=term|required=name,definition|optional=status,refs
15
+ record|type=command|required=id,name,use,scope,expectation|optional=risk,sensitivity,status,refs
16
+ record|type=workflow|required=id,name,when,steps,done|optional=forbid,askIf,haltIf,approval,risk,status,refs
17
+
18
+ record|type=runbook|required=name,scope,owner|optional=status,refs
19
+ record|type=workbook|required=name,phase,state|optional=status,refs
20
+ record|type=chain|required=step,command,expectExit|optional=status,refs
21
+ record|type=state|required=name,distTag,intent|optional=status,refs
22
+ record|type=transition|required=from,to,requires|optional=status,refs
23
+ record|type=promotion|required=from,to,requires|optional=status,refs
24
+ record|type=rollback|required=strategy,note|optional=status,refs
25
+ record|type=artifact|required=path,schema|optional=status,refs
26
+ record|type=config|required=key,default|optional=status,refs
27
+ record|type=cadence|required=rule|optional=status,refs
28
+ record|type=guardrail|required=id,level,directive,why|optional=status,refs
29
+
30
+ profile|name=core|requiredRecords=meta,ref,rule,check,decision,example,term,command,workflow
31
+ profile|name=runbook|requiredRecords=meta,ref,rule,check,decision,example,term,command,workflow,runbook,chain,artifact,state,transition,promotion,rollback,config,cadence,guardrail
32
+ profile|name=workbook|requiredRecords=meta,ref,rule,check,decision,example,term,command,workflow,workbook,state,transition,artifact,guardrail
33
+
34
+ defaults|omitOptional=true|omitEmpty=true|requiredFieldsExplicit=true
35
+ stop|criticalSecretRisk=true|destructiveUnapproved=true|policyConflictUnresolved=true
36
+ prompt|multiValidInterpretations=true|requiredApprovalMissing=true
37
+ warn|shouldViolation=true|lowRiskUncertainty=true
@@ -49,3 +49,231 @@ export type DocumentationBatchResult = {
49
49
  timestamp: string;
50
50
  };
51
51
  };
52
+
53
+ export type NormalizedRecordStatus = "active" | "deprecated" | "draft" | "observed" | "planned";
54
+
55
+ export type NormalizedBaseRecord = {
56
+ id?: string;
57
+ status?: NormalizedRecordStatus;
58
+ refs?: string[];
59
+ };
60
+
61
+ export type NormalizedMeta = NormalizedBaseRecord & {
62
+ schema: "base.v2";
63
+ doc: string;
64
+ truth: "canonical" | "observed" | "planned";
65
+ profile?: "core" | "runbook" | "workbook";
66
+ title?: string;
67
+ owner?: string;
68
+ tags?: string[];
69
+ };
70
+
71
+ export type NormalizedRef = NormalizedBaseRecord & {
72
+ id: string;
73
+ type: "adr" | "file" | "code" | "doc" | "issue" | "pr" | "test" | "external";
74
+ target: string;
75
+ anchor?: string;
76
+ label?: string;
77
+ note?: string;
78
+ };
79
+
80
+ export type NormalizedRule = NormalizedBaseRecord & {
81
+ id: string;
82
+ level: "must" | "must_not" | "should" | "may";
83
+ scope: string;
84
+ scope_kind?: string;
85
+ kind?: string;
86
+ directive: string;
87
+ why: string;
88
+ unless?: string;
89
+ also?: string[];
90
+ risk?: "low" | "medium" | "high" | "critical";
91
+ approval?: "none" | "prompt" | "required";
92
+ override?: "auto" | "warn" | "prompt" | "stop";
93
+ };
94
+
95
+ export type NormalizedCheck = NormalizedBaseRecord & {
96
+ id: string;
97
+ scope: string;
98
+ assertion: string;
99
+ when?: string;
100
+ onFail?: "auto" | "warn" | "prompt" | "stop";
101
+ };
102
+
103
+ export type NormalizedDecision = NormalizedBaseRecord & {
104
+ id: string;
105
+ topic: string;
106
+ choice: string;
107
+ why: string;
108
+ consequence?: string;
109
+ };
110
+
111
+ export type NormalizedExample = NormalizedBaseRecord & {
112
+ id: string;
113
+ for: string;
114
+ kind: "good" | "bad" | "edge";
115
+ text: string;
116
+ };
117
+
118
+ export type NormalizedTerm = NormalizedBaseRecord & {
119
+ name: string;
120
+ definition: string;
121
+ };
122
+
123
+ export type NormalizedCommand = NormalizedBaseRecord & {
124
+ id: string;
125
+ name: string;
126
+ use: string;
127
+ scope: string;
128
+ expectation: string;
129
+ risk?: "low" | "medium" | "high" | "critical";
130
+ sensitivity?: "non_sensitive" | "policy_sensitive";
131
+ };
132
+
133
+ export type NormalizedWorkflow = NormalizedBaseRecord & {
134
+ id: string;
135
+ name: string;
136
+ when: string;
137
+ steps: string[];
138
+ done: string[];
139
+ forbid?: string[];
140
+ askIf?: string;
141
+ haltIf?: string;
142
+ approval?: "none" | "prompt" | "required";
143
+ risk?: "low" | "medium" | "high" | "critical";
144
+ };
145
+
146
+ export type NormalizedRunbook = NormalizedBaseRecord & {
147
+ name: string;
148
+ scope: string;
149
+ owner: string;
150
+ };
151
+
152
+ export type NormalizedWorkbook = NormalizedBaseRecord & {
153
+ name: string;
154
+ phase: string;
155
+ state: string;
156
+ };
157
+
158
+ export type NormalizedChain = NormalizedBaseRecord & {
159
+ step: string;
160
+ command: string;
161
+ expectExit: number;
162
+ };
163
+
164
+ export type NormalizedState = NormalizedBaseRecord & {
165
+ name: string;
166
+ distTag: string;
167
+ intent: string;
168
+ };
169
+
170
+ export type NormalizedTransition = NormalizedBaseRecord & {
171
+ from: string;
172
+ to: string;
173
+ requires: string[];
174
+ };
175
+
176
+ export type NormalizedPromotion = NormalizedBaseRecord & {
177
+ from: string;
178
+ to: string;
179
+ requires: string[];
180
+ };
181
+
182
+ export type NormalizedRollback = NormalizedBaseRecord & {
183
+ strategy: string;
184
+ note: string;
185
+ };
186
+
187
+ export type NormalizedArtifact = NormalizedBaseRecord & {
188
+ path: string;
189
+ schema: string;
190
+ };
191
+
192
+ export type NormalizedConfig = NormalizedBaseRecord & {
193
+ key: string;
194
+ default: string;
195
+ };
196
+
197
+ export type NormalizedCadence = NormalizedBaseRecord & {
198
+ rule: string;
199
+ };
200
+
201
+ export type NormalizedGuardrail = NormalizedBaseRecord & {
202
+ id: string;
203
+ level: "must" | "must_not" | "should" | "may";
204
+ directive: string;
205
+ why: string;
206
+ };
207
+
208
+ export type NormalizedDocument = {
209
+ meta: NormalizedMeta | null;
210
+ refs: NormalizedRef[];
211
+ rules: NormalizedRule[];
212
+ checks: NormalizedCheck[];
213
+ decisions: NormalizedDecision[];
214
+ examples: NormalizedExample[];
215
+ terms: NormalizedTerm[];
216
+ commands: NormalizedCommand[];
217
+ workflows: NormalizedWorkflow[];
218
+ runbooks: NormalizedRunbook[];
219
+ workbooks: NormalizedWorkbook[];
220
+ chains: NormalizedChain[];
221
+ states: NormalizedState[];
222
+ transitions: NormalizedTransition[];
223
+ promotions: NormalizedPromotion[];
224
+ rollbacks: NormalizedRollback[];
225
+ artifacts: NormalizedArtifact[];
226
+ configs: NormalizedConfig[];
227
+ cadences: NormalizedCadence[];
228
+ guardrails: NormalizedGuardrail[];
229
+ refsById: Map<string, NormalizedRef>;
230
+ examplesByParent: Map<string, NormalizedExample[]>;
231
+ profileRecords: Map<"core" | "runbook" | "workbook", Array<NormalizedBaseRecord>>;
232
+ };
233
+
234
+ export type ViewModelSection = {
235
+ id: string;
236
+ title?: string;
237
+ description?: string;
238
+ renderer: string;
239
+ source:
240
+ | "meta"
241
+ | "refs"
242
+ | "rules"
243
+ | "checks"
244
+ | "decisions"
245
+ | "examples"
246
+ | "terms"
247
+ | "commands"
248
+ | "workflows"
249
+ | "runbooks"
250
+ | "workbooks"
251
+ | "chains"
252
+ | "states"
253
+ | "transitions"
254
+ | "promotions"
255
+ | "rollbacks"
256
+ | "artifacts"
257
+ | "configs"
258
+ | "cadences"
259
+ | "guardrails";
260
+ where?: Record<string, string | number | boolean>;
261
+ sortBy?: string[];
262
+ template?: string;
263
+ };
264
+
265
+ export type ViewRenderPolicy = {
266
+ id: string;
267
+ mode: "append" | "replace" | "fallback";
268
+ when?: string;
269
+ };
270
+
271
+ export type ViewModelDefinition = {
272
+ id: string;
273
+ version: number;
274
+ docType: string;
275
+ target: string;
276
+ profile?: "core" | "runbook" | "workbook";
277
+ sections: ViewModelSection[];
278
+ renderPolicies?: ViewRenderPolicy[];
279
+ };
@@ -0,0 +1,247 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import type { DocumentationValidationIssue } from "./types.js";
4
+ import { parseAiDocument } from "./parser.js";
5
+
6
+ export type AiValidationContext = {
7
+ strict: boolean;
8
+ workspacePath: string;
9
+ expectedDoc?: "rules" | "runbook" | "workbook";
10
+ };
11
+
12
+ const REF_TYPES = new Set(["adr", "file", "code", "doc", "issue", "pr", "test", "external"]);
13
+
14
+ const REQUIRED_BY_PROFILE: Record<string, string[]> = {
15
+ core: ["meta", "ref", "rule", "check", "decision", "example", "term", "command", "workflow"],
16
+ runbook: [
17
+ "meta",
18
+ "ref",
19
+ "rule",
20
+ "check",
21
+ "decision",
22
+ "example",
23
+ "term",
24
+ "command",
25
+ "workflow",
26
+ "runbook",
27
+ "chain",
28
+ "artifact",
29
+ "state",
30
+ "transition",
31
+ "promotion",
32
+ "rollback",
33
+ "config",
34
+ "cadence",
35
+ "guardrail"
36
+ ],
37
+ workbook: [
38
+ "meta",
39
+ "ref",
40
+ "rule",
41
+ "check",
42
+ "decision",
43
+ "example",
44
+ "term",
45
+ "command",
46
+ "workflow",
47
+ "workbook",
48
+ "state",
49
+ "transition",
50
+ "artifact",
51
+ "guardrail"
52
+ ]
53
+ };
54
+
55
+ function isAllowedMetaDoc(doc: string): boolean {
56
+ return (
57
+ doc === "rules" ||
58
+ doc === "runbook" ||
59
+ doc === "workbook" ||
60
+ doc === "generator" ||
61
+ doc === "map" ||
62
+ doc === "workflows" ||
63
+ doc === "commands" ||
64
+ doc === "decisions" ||
65
+ doc === "glossary" ||
66
+ doc === "observed" ||
67
+ doc === "planned" ||
68
+ doc === "checks" ||
69
+ doc === "manifest"
70
+ );
71
+ }
72
+
73
+ function profileForDoc(doc: string | undefined, explicitProfile: string | undefined): "core" | "runbook" | "workbook" {
74
+ if (explicitProfile === "core" || explicitProfile === "runbook" || explicitProfile === "workbook") {
75
+ return explicitProfile;
76
+ }
77
+ if (doc === "runbook") return "runbook";
78
+ if (doc === "workbook") return "workbook";
79
+ return "core";
80
+ }
81
+
82
+ export function validateAiSchema(aiOutput: string, ctx: AiValidationContext): DocumentationValidationIssue[] {
83
+ const issues: DocumentationValidationIssue[] = [];
84
+ const records = parseAiDocument(aiOutput);
85
+ if (records.length === 0) {
86
+ return [{ check: "schema", message: "AI output is empty", resolved: false }];
87
+ }
88
+
89
+ const meta = records[0];
90
+ if (!meta || meta.type !== "meta") {
91
+ return [{ check: "schema", message: "AI output must start with a meta record", resolved: false }];
92
+ }
93
+
94
+ const schema = meta.kv["schema"];
95
+ const doc = meta.kv["doc"];
96
+ const truth = meta.kv["truth"];
97
+ const status = meta.kv["status"] ?? meta.kv["st"];
98
+ const profile = profileForDoc(doc, meta.kv["profile"]);
99
+ const isLegacySchema = schema !== "base.v2";
100
+ if (schema !== "base.v2") {
101
+ issues.push({
102
+ check: "schema",
103
+ message: `AI meta.schema must be 'base.v2' (found '${schema ?? ""}')`,
104
+ resolved: true
105
+ });
106
+ }
107
+ if (!doc || !isAllowedMetaDoc(doc)) {
108
+ issues.push({ check: "schema", message: `Unsupported meta.doc '${doc ?? ""}'`, resolved: false });
109
+ }
110
+ if (!truth) issues.push({ check: "schema", message: "AI meta.truth is required", resolved: false });
111
+ if (!status) issues.push({ check: "schema", message: "AI meta.status is required", resolved: false });
112
+ if (ctx.expectedDoc && doc && ctx.expectedDoc !== doc) {
113
+ issues.push({
114
+ check: "schema",
115
+ message: `meta.doc '${doc}' does not match expected doc family for '${ctx.expectedDoc}'`,
116
+ resolved: !ctx.strict
117
+ });
118
+ }
119
+
120
+ const presentByType: Record<string, boolean> = { meta: true };
121
+ const knownIds = new Set<string>();
122
+ for (const rec of records.slice(1)) {
123
+ presentByType[rec.type] = true;
124
+ const id = rec.kv["id"];
125
+ if (id) knownIds.add(id);
126
+ if (rec.kv["name"]) knownIds.add(rec.kv["name"]);
127
+ }
128
+
129
+ for (const rec of records.slice(1)) {
130
+ if (rec.type === "rule" && !rec.kv["why"]) {
131
+ issues.push({
132
+ check: "schema",
133
+ message: "rule records require why",
134
+ resolved: isLegacySchema || !ctx.strict
135
+ });
136
+ }
137
+
138
+ if (rec.type === "ref") {
139
+ const type = rec.kv["type"];
140
+ const target = rec.kv["target"] ?? rec.kv["path"];
141
+ const legacyPath = rec.kv["path"];
142
+ if (!rec.kv["id"] || !type || !target) {
143
+ issues.push({
144
+ check: "schema",
145
+ message: "ref records require id, type, target",
146
+ resolved: isLegacySchema || !ctx.strict
147
+ });
148
+ if (legacyPath && !existsSync(resolve(ctx.workspacePath, legacyPath))) {
149
+ issues.push({
150
+ check: "schema",
151
+ message: `ref.path does not exist: '${legacyPath}'`,
152
+ resolved: !ctx.strict
153
+ });
154
+ }
155
+ } else if (!REF_TYPES.has(type)) {
156
+ issues.push({
157
+ check: "schema",
158
+ message: `ref.type '${type}' must be one of ${[...REF_TYPES].join(", ")}`,
159
+ resolved: isLegacySchema || !ctx.strict
160
+ });
161
+ } else if ((type === "file" || type === "code" || type === "doc") && !existsSync(resolve(ctx.workspacePath, target))) {
162
+ issues.push({
163
+ check: "schema",
164
+ message: `ref.target does not exist: '${target}'`,
165
+ resolved: !ctx.strict
166
+ });
167
+ }
168
+ }
169
+
170
+ if (rec.type === "example") {
171
+ const parent = rec.kv["for"];
172
+ const kind = rec.kv["kind"];
173
+ if (!parent || !knownIds.has(parent)) {
174
+ issues.push({
175
+ check: "schema",
176
+ message: `example.for must reference an existing record id/name (found '${parent ?? ""}')`,
177
+ resolved: isLegacySchema || !ctx.strict
178
+ });
179
+ }
180
+ if (!kind || !["good", "bad", "edge"].includes(kind)) {
181
+ issues.push({
182
+ check: "schema",
183
+ message: "example.kind must be one of good|bad|edge",
184
+ resolved: isLegacySchema || !ctx.strict
185
+ });
186
+ }
187
+ }
188
+ }
189
+
190
+ const isActive = status === "active";
191
+ if (isActive) {
192
+ // Preserve strict runbook/workbook/rules baseline behavior during v2 migration.
193
+ if (doc === "runbook" && !presentByType["rule"] && !presentByType["chain"]) {
194
+ issues.push({
195
+ check: "schema",
196
+ message: "Missing required AI records for doc family 'runbook': at least one rule| or chain| record",
197
+ resolved: !ctx.strict
198
+ });
199
+ }
200
+ if (doc === "workbook" && !presentByType["command"]) {
201
+ issues.push({
202
+ check: "schema",
203
+ message: "Missing required AI records for doc family 'workbook': at least one command| record",
204
+ resolved: !ctx.strict
205
+ });
206
+ }
207
+ if (doc === "workbook" && !presentByType["config"]) {
208
+ issues.push({
209
+ check: "schema",
210
+ message: "Missing required AI records for doc family 'workbook': at least one config| record",
211
+ resolved: !ctx.strict
212
+ });
213
+ }
214
+ if (doc === "rules" && !presentByType["rule"] && !presentByType["check"]) {
215
+ issues.push({
216
+ check: "schema",
217
+ message: "Missing required AI records for doc family 'rules': at least one rule| or check| record",
218
+ resolved: !ctx.strict
219
+ });
220
+ }
221
+
222
+ const missing = REQUIRED_BY_PROFILE[profile]
223
+ .filter((type) => {
224
+ if (type === "workflow") return !presentByType["workflow"] && !presentByType["wf"];
225
+ if (type === "command") return !presentByType["command"] && !presentByType["cmd"];
226
+ if (type === "example") return !presentByType["example"];
227
+ return !presentByType[type];
228
+ })
229
+ .map((t) => `${t}| record`);
230
+ if (missing.length > 0) {
231
+ issues.push({
232
+ check: "schema",
233
+ message: `Missing required AI records for profile '${profile}': ${missing.join(", ")}`,
234
+ resolved: isLegacySchema || !ctx.strict
235
+ });
236
+ }
237
+ }
238
+
239
+ return issues;
240
+ }
241
+
242
+ export function autoResolveAiSchema(aiOutput: string): string {
243
+ if (aiOutput.startsWith("meta|schema=") || aiOutput.startsWith("meta|v=")) {
244
+ return aiOutput;
245
+ }
246
+ return `meta|schema=base.v2|doc=rules|truth=canonical|status=draft|profile=core\n\n${aiOutput}`;
247
+ }