1// SPDX-License-Identifier: Apache-2.0
2
3// Schema lifecycle: experimental | stable | deprecated
4@status("experimental")
5package gemara
6
7import "list"
8
9@go(gemara)
10
11// GuidanceCatalog represents a concerted documentation effort to help bring about an optimal future without foreknowledge of the implementation details
12#GuidanceCatalog: {
13 #Catalog
14 metadata: type: "GuidanceCatalog"
15
16 // type categorizes this document based on the intent of its contents
17 type: #GuidanceType @go(GuidanceType)
18
19 // front-matter provides introductory text for the document to be used during rendering
20 "front-matter"?: string @go(FrontMatter) @yaml("front-matter,omitempty")
21
22 // guidelines is a list of unique guidelines defined by this catalog
23 guidelines?: [#Guideline, ...#Guideline] @go(Guidelines)
24
25 // exemptions provides information about situations where this guidance is not applicable
26 exemptions?: [#Exemption, ...#Exemption] @go(Exemptions)
27
28 if guidelines != _|_ {
29 _uniqueGuidelineIds: {for i, g in guidelines {(g.id): i}}
30 groups: [#Group, ...#Group]
31 let _validGroupIds = [for g in groups {g.id}]
32
33 // Unify the valid ID list with a list.Contains constraint to require each entry's value exists
34 for i, g in guidelines {
35 _groupValidation: "\(i)": _validGroupIds & list.Contains(g.group)
36 }
37 if metadata."applicability-groups" != _|_ {
38 let _validApplicabilityIds = [for ag in metadata."applicability-groups" {ag.id}]
39 for i, g in guidelines if g.applicability != _|_ {
40 for j, a in g.applicability {
41 _applicabilityValidation: "\(i)-\(j)": _validApplicabilityIds & list.Contains(a)
42 }
43 }
44 }
45 }
46}
47
48// GuidanceType restricts the possible types that a catalog may be listed as
49#GuidanceType: "Standard" | "Regulation" | "Best Practice" | "Framework" @go(-)
50
51// Exemption describes a single scenario where the catalog is not applicable
52#Exemption: {
53 // description identifies who or what is exempt from the full guidance
54 description: string
55
56 // reason explains why the exemption is granted
57 reason: string
58
59 // redirect points to alternative guidelines or controls that should be followed instead
60 redirect?: #MultiEntryMapping @go(Redirect,optional=nillable)
61}
62
63// Guideline provides explanatory context and recommendations for designing optimal outcomes
64#Guideline: {
65 // id allows this entry to be referenced by other elements
66 id: string
67
68 // title describes the contents of this guideline
69 title: string
70
71 // objective is a unified statement of intent, which may encompass multiple situationally applicable statements
72 objective: string
73
74 // group provides an id to the group that this guideline belongs to
75 group: string @go(Group)
76
77 // recommendations is a list of non-binding suggestions to aid in evaluation or enforcement of the guideline
78 recommendations?: [string, ...string]
79
80 // extends is an id for a guideline which this guideline adds to, in this document or elsewhere
81 extends?: #EntryMapping @go(Extends,optional=nillable)
82
83 // applicability specifies the contexts in which this guideline applies
84 applicability?: [string, ...string] @go(Applicability)
85
86 // rationale provides the context for this guideline
87 rationale?: #Rationale @go(Rationale,optional=nillable)
88
89 // statements is a list of structural sub-requirements within a guideline
90 statements?: [#Statement, ...#Statement] @go(Statements)
91
92 // principles documents the relationship between this guideline and one or more principles
93 "principles"?: [#MultiEntryMapping, ...#MultiEntryMapping] @go(Principles) @yaml("principles,omitempty")
94
95 // vector-mappings documents the relationship between this guideline and one or more vectors
96 "vectors"?: [#MultiEntryMapping, ...#MultiEntryMapping] @go(Vectors) @yaml("vectors,omitempty")
97
98 // see-also lists related guideline IDs within the same GuidanceCatalog
99 "see-also"?: [string, ...string] @go(SeeAlso) @yaml("see-also,omitempty")
100
101 // state is the lifecycle state of this guideline
102 state: #Lifecycle @go(State) @yaml("state,omitempty")
103
104 // replaced-by references the guideline that supersedes this one when deprecated or retired
105 "replaced-by"?: #EntryMapping @go(ReplacedBy,optional=nillable) @yaml("replaced-by,omitempty")
106
107 // retired guidelines must not have recommendations
108 if state == "Retired" {
109 recommendations?: _|_
110 }
111}
112
113// Statement represents a structural sub-requirement within a guideline;
114// They do not increase strictness and all statements within a guideline apply together
115#Statement: {
116 // id allows this entry to be referenced by other elements
117 id: string
118
119 // title describes the contents of this statement
120 title?: string
121
122 // text is the body of this statement
123 text: string
124
125 // recommendations is a list of non-binding suggestions to aid in evaluation or enforcement of the statement
126 recommendations?: [string, ...string]
127}
128
129// Rationale provides a structured way to communicate a guideline author's intent
130#Rationale: {
131 // importance is an explanation of why this guideline matters
132 importance: string
133
134 // goals is a list of outcomes this guideline seeks to achieve
135 goals: [string, ...string]
136}