+
parameters |
@@ -448,13 +292,13 @@ digraph "None" {
];
- "Proposal Template" [
- id="Proposal Template";
+ "Comment Moderation Action" [
+ id="Comment Moderation Action";
label=<
-
- Proposal Template
+ |
+ Comment Moderation Action
|
@@ -462,7 +306,7 @@ digraph "None" {
content type |
- application/schema+json |
+ application/json |
@@ -472,7 +316,7 @@ digraph "None" {
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 5e60e623-ad02-4a1b-a1ac-406db978ee48 b679ded3-0e7c-41ba-89f8-da62a17898ea a5d232b8-5e03-4117-9afd-be32b878fcdd |
@@ -498,21 +342,11 @@ digraph "None" {
-
-
-
- template |
- Proposal Meta Template |
-
-
- |
-
-
-
+ |
- parameters |
- Brand Parameters Campaign Parameters Category Parameters |
+ ref |
+ Proposal Comment |
|
@@ -523,13 +357,13 @@ digraph "None" {
];
- "Proposal" [
- id="Proposal";
+ "Rep Nomination" [
+ id="Rep Nomination";
label=<
-
- Proposal
+ |
+ Rep Nomination
|
@@ -547,7 +381,7 @@ digraph "None" {
type |
- 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ bf9abd97-5d1f-4429-8e80-740fea371a9c 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
@@ -573,21 +407,21 @@ digraph "None" {
-
+ |
- template |
- Proposal Template |
+ ref |
+ Rep Profile |
|
-
+ |
- collaborators |
- Collaborators Reference List |
+ template |
+ Rep Nomination Form Template |
|
@@ -607,7 +441,7 @@ digraph "None" {
parameters |
- Brand Parameters Campaign Parameters Category Parameters |
+ Contest Parameters |
@@ -618,13 +452,13 @@ digraph "None" {
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Contest Parameters" [
+ id="Contest Parameters";
label=<
-
- Proposal Comment Template
+ |
+ Contest Parameters
|
@@ -632,7 +466,7 @@ digraph "None" {
content type |
- application/schema+json |
+ application/json |
@@ -642,7 +476,7 @@ digraph "None" {
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 60185874-7e13-407c-a06c-238ffe637ae6 788ff4c6-d65a-451f-bb33-575fe056b411 |
@@ -672,7 +506,27 @@ digraph "None" {
template |
- Proposal Comment Meta Template |
+ Contest Parameters Form Template |
+
+
+
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
|
@@ -693,13 +547,78 @@ digraph "None" {
];
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Contest Delegation" [
+ id="Contest Delegation";
+ label=<
+
+
+
+ Contest Delegation
+ |
+
+
+
+
+
+ type |
+ 764f17fb-cc50-4979-b14a-b213dbac5994 788ff4c6-d65a-451f-bb33-575fe056b411 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ ref |
+ Rep Nomination |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Contest Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters Form Template" [
+ id="Contest Parameters Form Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Contest Parameters Form Template
|
@@ -717,7 +636,7 @@ digraph "None" {
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 60185874-7e13-407c-a06c-238ffe637ae6 788ff4c6-d65a-451f-bb33-575fe056b411 |
@@ -742,29 +661,19 @@ digraph "None" {
-
-
-
-
- parameters |
- Brand Parameters Campaign Parameters Category Parameters |
-
-
- |
-
>
];
- "Proposal Meta Template" [
- id="Proposal Meta Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Meta Template
+ |
+ Proposal Form Template
|
@@ -782,7 +691,7 @@ digraph "None" {
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -823,13 +732,13 @@ digraph "None" {
];
- "Proposal Moderation Action" [
- id="Proposal Moderation Action";
+ "Proposal" [
+ id="Proposal";
label=<
-
- Proposal Moderation Action
+ |
+ Proposal
|
@@ -847,7 +756,7 @@ digraph "None" {
type |
- 5e60e623-ad02-4a1b-a1ac-406db978ee48 7808d2ba-d511-40af-84e8-c0d1625fdfdc a5d232b8-5e03-4117-9afd-be32b878fcdd |
+ 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -873,11 +782,41 @@ digraph "None" {
-
+ |
- ref |
- Proposal |
+ template |
+ Proposal Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters Campaign Parameters Category Parameters |
|
@@ -888,13 +827,13 @@ digraph "None" {
];
- "Proposal Submission Action" [
- id="Proposal Submission Action";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
label=<
-
- Proposal Submission Action
+ |
+ Proposal Comment Form Template
|
@@ -902,7 +841,7 @@ digraph "None" {
content type |
- application/json |
+ application/schema+json |
@@ -912,7 +851,7 @@ digraph "None" {
type |
- 5e60e623-ad02-4a1b-a1ac-406db978ee48 7808d2ba-d511-40af-84e8-c0d1625fdfdc 78927329-cfd9-4ea1-9c71-0e019b126a65 |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -938,17 +877,7 @@ digraph "None" {
-
-
- |
-
-
-
+ |
parameters |
@@ -963,23 +892,800 @@ digraph "None" {
];
+ "Proposal Comment Presentation Template" [
+ id="Proposal Comment Presentation Template";
+ label=<
+
+
+
+ Proposal Comment Presentation Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ cb99b9bd-681a-49d8-9836-89107c02e8ef b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters Campaign Parameters Category Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Proposal Moderation Action" [
+ id="Proposal Moderation Action";
+ label=<
+
+
+
+ Proposal Moderation Action
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 5e60e623-ad02-4a1b-a1ac-406db978ee48 7808d2ba-d511-40af-84e8-c0d1625fdfdc a5d232b8-5e03-4117-9afd-be32b878fcdd |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Proposal Presentation Template" [
+ id="Proposal Presentation Template";
+ label=<
+
+
+
+ Proposal Presentation Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ cb99b9bd-681a-49d8-9836-89107c02e8ef 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters Campaign Parameters Category Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Proposal Submission Action" [
+ id="Proposal Submission Action";
+ label=<
+
+
+
+ Proposal Submission Action
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 5e60e623-ad02-4a1b-a1ac-406db978ee48 7808d2ba-d511-40af-84e8-c0d1625fdfdc 78927329-cfd9-4ea1-9c71-0e019b126a65 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters Campaign Parameters Category Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Profile" [
+ id="Rep Profile";
+ label=<
+
+
+
+ Rep Profile
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0f2c86a2-ffda-40b0-ad38-23709e1c10b3 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Rep Profile Form Template |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination Form Template" [
+ id="Rep Nomination Form Template";
+ label=<
+
+
+
+ Rep Nomination Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f bf9abd97-5d1f-4429-8e80-740fea371a9c 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Contest Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Profile Form Template" [
+ id="Rep Profile Form Template";
+ label=<
+
+
+
+ Rep Profile Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0f2c86a2-ffda-40b0-ad38-23709e1c10b3 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 ebcabeeb-5bc5-4f95-91e8-cab8ca724172 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Brand Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 5ef32d5d-f240-462c-a7a4-ba4af221fa23 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Campaign Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 818938c3-3139-4daa-afe6-974c78488e95 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Category Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Campaign Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Brand Parameters":"template":e -> "Brand Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Campaign Parameters":"template":e -> "Campaign Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Campaign Parameters":"parameters":e -> "Brand Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Category Parameters":"template":e -> "Category Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Category Parameters":"parameters":e -> "Campaign Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Comment Moderation Action":"ref":e -> "Proposal Comment":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Decision Parameters":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal":"template":e -> "Proposal Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Delegation":"ref":e -> "Rep Nomination":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Delegation":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Parameters":"template":e -> "Contest Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Parameters":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal":"template":e -> "Proposal Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Comment":"ref":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Comment":"template":e -> "Proposal Comment Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Comment":"template":e -> "Proposal Comment Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Comment":"reply":e -> "Proposal Comment":"title":n [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Comment":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Meta Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Template":"template":e -> "Proposal Comment Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Comment Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Meta Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Presentation Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Moderation Action":"ref":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Presentation Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Submission Action":"ref":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Submission Action":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Template":"template":e -> "Proposal Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Nomination":"ref":e -> "Rep Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"template":e -> "Rep Nomination Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination Form Template":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Profile":"template":e -> "Rep Profile Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Profile":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Profile Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters.dot
index ec4702ddac..f260bb12cc 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters.dot
@@ -13,89 +13,28 @@ Relationships"
- subgraph cluster_system_parameters {
- label = "System Parameters";
- color=blue
- penwidth=20
-
- "Brand Parameters" [
- id="Brand Parameters";
- label=<
-
-
-
- Brand Parameters
- |
-
-
-
-
-
- content type |
- application/json |
-
-
- |
-
-
-
-
-
- type |
- ebcabeeb-5bc5-4f95-91e8-cab8ca724172 |
-
-
- |
-
-
-
-
- |
-
-
-
-
-
- ver |
- Document Ver |
-
-
- |
-
-
-
- >
- ];
-
-
- "Campaign Parameters" [
- id="Campaign Parameters";
- label=<
-
-
-
- Campaign Parameters
- |
-
+ "Brand Parameters Form Template" [
+ id="Brand Parameters Form Template";
+ label=<
+
+
+
+ Brand Parameters Form Template
+ |
+
-
- >
- ];
+
+ >
+ ];
- }
- "Decision Parameters" [
- id="Decision Parameters";
+ "Contest Parameters" [
+ id="Contest Parameters";
label=<
-
- Decision Parameters
+ |
+ Contest Parameters
|
@@ -134,13 +73,28 @@ Relationships"
];
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
+ label=<
+
+
+
+ Proposal Comment Form Template
+ |
+
+
+
+ >
+ ];
+
+
+ "Proposal Comment Presentation Template" [
+ id="Proposal Comment Presentation Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Proposal Comment Presentation Template
|
@@ -149,13 +103,13 @@ Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Comment Template
+ |
+ Proposal Form Template
|
@@ -164,13 +118,13 @@ Relationships"
];
- "Proposal Meta Template" [
- id="Proposal Meta Template";
+ "Proposal Presentation Template" [
+ id="Proposal Presentation Template";
label=<
-
- Proposal Meta Template
+ |
+ Proposal Presentation Template
|
@@ -194,13 +148,28 @@ Relationships"
];
- "Proposal Template" [
- id="Proposal Template";
+ "Rep Profile" [
+ id="Rep Profile";
+ label=<
+
+
+
+ Rep Profile
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Profile Form Template" [
+ id="Rep Profile Form Template";
label=<
-
- Proposal Template
+ |
+ Rep Profile Form Template
|
@@ -209,13 +178,122 @@ Relationships"
];
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 ebcabeeb-5bc5-4f95-91e8-cab8ca724172 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Brand Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Brand Parameters":"template":e -> "Brand Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Campaign Parameters":"title":e -> "Brand Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Decision Parameters":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Contest Parameters":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Comment":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Meta Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Meta Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Form Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Presentation Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Form Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Presentation Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Submission Action":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Profile":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Profile Form Template":"title":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters_form_template.dot
new file mode 100644
index 0000000000..d026ecbce4
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/brand_parameters_form_template.dot
@@ -0,0 +1,93 @@
+digraph "Brand Parameters Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Brand Parameters Form Template
+Document Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Brand Parameters Form Template" [
+ id="Brand Parameters Form Template";
+ label=<
+
+
+
+ Brand Parameters Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 60185874-7e13-407c-a06c-238ffe637ae6 ebcabeeb-5bc5-4f95-91e8-cab8ca724172 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Brand Parameters":"title":e -> "Brand Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters.dot
index f21afdeadf..58d8fafabc 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters.dot
@@ -13,114 +13,28 @@ Relationships"
- subgraph cluster_system_parameters {
- label = "System Parameters";
- color=blue
- penwidth=20
-
- "Brand Parameters" [
- id="Brand Parameters";
- label=<
-
-
-
- Brand Parameters
- |
-
-
-
- >
- ];
-
-
- "Campaign Parameters" [
- id="Campaign Parameters";
- label=<
-
-
-
- Campaign Parameters
- |
-
-
-
-
-
- content type |
- application/json |
-
-
- |
-
-
-
-
-
- type |
- 5ef32d5d-f240-462c-a7a4-ba4af221fa23 |
-
-
- |
-
-
-
-
- |
-
-
-
-
-
- ver |
- Document Ver |
-
-
- |
-
-
-
-
-
- parameters |
- Brand Parameters |
-
-
- |
-
-
-
- >
- ];
-
-
- "Category Parameters" [
- id="Category Parameters";
- label=<
-
-
-
- Category Parameters
- |
-
+ "Campaign Parameters Form Template" [
+ id="Campaign Parameters Form Template";
+ label=<
+
+
+
+ Campaign Parameters Form Template
+ |
+
-
- >
- ];
+
+ >
+ ];
- }
- "Decision Parameters" [
- id="Decision Parameters";
+ "Contest Parameters" [
+ id="Contest Parameters";
label=<
-
- Decision Parameters
+ |
+ Contest Parameters
|
@@ -159,13 +73,13 @@ Relationships"
];
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Proposal Comment Form Template
|
@@ -174,13 +88,13 @@ Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Proposal Comment Presentation Template" [
+ id="Proposal Comment Presentation Template";
label=<
-
- Proposal Comment Template
+ |
+ Proposal Comment Presentation Template
|
@@ -189,13 +103,13 @@ Relationships"
];
- "Proposal Meta Template" [
- id="Proposal Meta Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Meta Template
+ |
+ Proposal Form Template
|
@@ -204,13 +118,13 @@ Relationships"
];
- "Proposal Submission Action" [
- id="Proposal Submission Action";
+ "Proposal Presentation Template" [
+ id="Proposal Presentation Template";
label=<
-
- Proposal Submission Action
+ |
+ Proposal Presentation Template
|
@@ -219,13 +133,13 @@ Relationships"
];
- "Proposal Template" [
- id="Proposal Template";
+ "Proposal Submission Action" [
+ id="Proposal Submission Action";
label=<
-
- Proposal Template
+ |
+ Proposal Submission Action
|
@@ -234,14 +148,146 @@ Relationships"
];
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 5ef32d5d-f240-462c-a7a4-ba4af221fa23 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Campaign Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Campaign Parameters":"template":e -> "Campaign Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Campaign Parameters":"parameters":e -> "Brand Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Category Parameters":"title":e -> "Campaign Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Decision Parameters":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Contest Parameters":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Comment":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Meta Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Meta Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Form Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Presentation Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Form Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Presentation Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Submission Action":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Template":"title":e -> "Campaign Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters_form_template.dot
new file mode 100644
index 0000000000..3f72dfb6ae
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/campaign_parameters_form_template.dot
@@ -0,0 +1,94 @@
+digraph "Campaign Parameters Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Campaign Parameters Form
+Template Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Campaign Parameters Form Template" [
+ id="Campaign Parameters Form Template";
+ label=<
+
+
+
+ Campaign Parameters Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 60185874-7e13-407c-a06c-238ffe637ae6 5ef32d5d-f240-462c-a7a4-ba4af221fa23 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Campaign Parameters":"title":e -> "Campaign Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters.dot
index b6a2aa470a..b010bf86ab 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters.dot
@@ -13,99 +13,28 @@ Relationships"
- subgraph cluster_system_parameters {
- label = "System Parameters";
- color=blue
- penwidth=20
-
- "Campaign Parameters" [
- id="Campaign Parameters";
- label=<
-
-
-
- Campaign Parameters
- |
-
-
-
- >
- ];
-
-
- "Category Parameters" [
- id="Category Parameters";
- label=<
-
-
-
- Category Parameters
- |
-
-
-
-
-
- content type |
- application/json |
-
-
- |
-
-
-
-
-
- type |
- 818938c3-3139-4daa-afe6-974c78488e95 |
-
-
- |
-
-
-
-
- |
-
-
-
-
-
- ver |
- Document Ver |
-
-
- |
-
-
-
-
-
- parameters |
- Campaign Parameters |
-
-
- |
-
+ "Category Parameters Form Template" [
+ id="Category Parameters Form Template";
+ label=<
+
+
+
+ Category Parameters Form Template
+ |
+
-
- >
- ];
+
+ >
+ ];
- }
- "Decision Parameters" [
- id="Decision Parameters";
+ "Contest Parameters" [
+ id="Contest Parameters";
label=<
-
- Decision Parameters
+ |
+ Contest Parameters
|
@@ -144,13 +73,13 @@ Relationships"
];
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Proposal Comment Form Template
|
@@ -159,13 +88,13 @@ Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Proposal Comment Presentation Template" [
+ id="Proposal Comment Presentation Template";
label=<
-
- Proposal Comment Template
+ |
+ Proposal Comment Presentation Template
|
@@ -174,13 +103,13 @@ Relationships"
];
- "Proposal Meta Template" [
- id="Proposal Meta Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Meta Template
+ |
+ Proposal Form Template
|
@@ -189,13 +118,13 @@ Relationships"
];
- "Proposal Submission Action" [
- id="Proposal Submission Action";
+ "Proposal Presentation Template" [
+ id="Proposal Presentation Template";
label=<
-
- Proposal Submission Action
+ |
+ Proposal Presentation Template
|
@@ -204,13 +133,13 @@ Relationships"
];
- "Proposal Template" [
- id="Proposal Template";
+ "Proposal Submission Action" [
+ id="Proposal Submission Action";
label=<
-
- Proposal Template
+ |
+ Proposal Submission Action
|
@@ -219,13 +148,130 @@ Relationships"
];
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 818938c3-3139-4daa-afe6-974c78488e95 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Category Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Campaign Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Category Parameters":"template":e -> "Category Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Category Parameters":"parameters":e -> "Campaign Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Decision Parameters":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Contest Parameters":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Comment":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Meta Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Meta Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Form Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment Presentation Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Form Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Presentation Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Submission Action":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Template":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters_form_template.dot
new file mode 100644
index 0000000000..a142233fc5
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters_form_template.dot
@@ -0,0 +1,94 @@
+digraph "Category Parameters Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Category Parameters Form
+Template Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Category Parameters Form Template" [
+ id="Category Parameters Form Template";
+ label=<
+
+
+
+ Category Parameters Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 60185874-7e13-407c-a06c-238ffe637ae6 818938c3-3139-4daa-afe6-974c78488e95 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Category Parameters":"title":e -> "Category Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_delegation.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_delegation.dot
new file mode 100644
index 0000000000..e271581e8c
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_delegation.dot
@@ -0,0 +1,113 @@
+digraph "Contest Delegation" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Contest Delegation Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Rep Nomination" [
+ id="Rep Nomination";
+ label=<
+
+
+
+ Rep Nomination
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters" [
+ id="Contest Parameters";
+ label=<
+
+
+
+ Contest Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Delegation" [
+ id="Contest Delegation";
+ label=<
+
+
+
+ Contest Delegation
+ |
+
+
+
+
+
+ type |
+ 764f17fb-cc50-4979-b14a-b213dbac5994 788ff4c6-d65a-451f-bb33-575fe056b411 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ ref |
+ Rep Nomination |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Contest Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Delegation":"ref":e -> "Rep Nomination":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Delegation":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters.dot
new file mode 100644
index 0000000000..08485598c4
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters.dot
@@ -0,0 +1,227 @@
+digraph "Contest Parameters" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Contest Parameters Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Contest Parameters Form Template" [
+ id="Contest Parameters Form Template";
+ label=<
+
+
+
+ Contest Parameters Form Template
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters" [
+ id="Contest Parameters";
+ label=<
+
+
+
+ Contest Parameters
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ 60185874-7e13-407c-a06c-238ffe637ae6 788ff4c6-d65a-451f-bb33-575fe056b411 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ template |
+ Contest Parameters Form Template |
+
+
+ |
+
+
+
+
+
+ collaborators |
+ Collaborators Reference List |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters Campaign Parameters Category Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Delegation" [
+ id="Contest Delegation";
+ label=<
+
+
+
+ Contest Delegation
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination" [
+ id="Rep Nomination";
+ label=<
+
+
+
+ Rep Nomination
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination Form Template" [
+ id="Rep Nomination Form Template";
+ label=<
+
+
+
+ Rep Nomination Form Template
+ |
+
+
+
+ >
+ ];
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Contest Parameters":"template":e -> "Contest Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Parameters":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Contest Delegation":"title":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"title":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination Form Template":"title":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters_form_template.dot
new file mode 100644
index 0000000000..3ea9b1438d
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/contest_parameters_form_template.dot
@@ -0,0 +1,88 @@
+digraph "Contest Parameters Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Contest Parameters Form
+Template Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Contest Parameters Form Template" [
+ id="Contest Parameters Form Template";
+ label=<
+
+
+
+ Contest Parameters Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 60185874-7e13-407c-a06c-238ffe637ae6 788ff4c6-d65a-451f-bb33-575fe056b411 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters" [
+ id="Contest Parameters";
+ label=<
+
+
+
+ Contest Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters":"title":e -> "Contest Parameters Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal.dot
index d7140c8a11..3c708d521e 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal.dot
@@ -13,13 +13,13 @@ Relationships"
- "Proposal Template" [
- id="Proposal Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Template
+ |
+ Proposal Form Template
|
@@ -82,7 +82,7 @@ Relationships"
template |
- Proposal Template |
+ Proposal Form Template |
@@ -219,7 +219,7 @@ Relationships"
}
- "Proposal":"template":e -> "Proposal Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal":"template":e -> "Proposal Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Proposal Comment":"title":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Moderation Action":"title":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment.dot
index 983953798b..376557c355 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment.dot
@@ -28,13 +28,13 @@ Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
label=<
-
- Proposal Comment Template
+ |
+ Proposal Comment Form Template
|
@@ -107,7 +107,7 @@ Relationships"
template |
- Proposal Comment Template |
+ Proposal Comment Form Template |
@@ -225,7 +225,7 @@ Relationships"
}
"Proposal Comment":"ref":e -> "Proposal":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Comment":"template":e -> "Proposal Comment Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Comment":"template":e -> "Proposal Comment Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Comment":"reply":e -> "Proposal Comment":"title":n [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
"Proposal Comment":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
"Comment Moderation Action":"title":e -> "Proposal Comment":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_meta_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_form_template.dot
similarity index 86%
rename from docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_meta_template.dot
rename to docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_form_template.dot
index 068613702a..6644a8dd9a 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_meta_template.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_form_template.dot
@@ -1,11 +1,11 @@
-digraph "Proposal Comment Meta Template" {
+digraph "Proposal Comment Form Template" {
rankdir="LR"
graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
labelloc="t"
- label="Proposal Comment Meta Template
+ label="Proposal Comment Form Template
Document Relationships"
fontcolor="#1d71b8"
fontsize=50
@@ -64,13 +64,13 @@ Document Relationships"
}
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Proposal Comment Form Template" [
+ id="Proposal Comment Form Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Proposal Comment Form Template
|
@@ -88,7 +88,7 @@ Document Relationships"
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -129,13 +129,13 @@ Document Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Proposal Comment" [
+ id="Proposal Comment";
label=<
-
- Proposal Comment Template
+ |
+ Proposal Comment
|
@@ -144,6 +144,6 @@ Document Relationships"
];
- "Proposal Comment Meta Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment Template":"title":e -> "Proposal Comment Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Comment Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Comment":"title":e -> "Proposal Comment Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_presentation_template.dot
similarity index 67%
rename from docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_template.dot
rename to docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_presentation_template.dot
index 7f43a69247..8d5ad2531c 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_template.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_presentation_template.dot
@@ -1,11 +1,12 @@
-digraph "Proposal Template" {
+digraph "Proposal Comment Presentation Template" {
rankdir="LR"
graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
labelloc="t"
- label="Proposal Template Document
+ label="Proposal Comment Presentation
+Template Document
Relationships"
fontcolor="#1d71b8"
fontsize=50
@@ -13,28 +14,64 @@ Relationships"
- "Proposal Meta Template" [
- id="Proposal Meta Template";
- label=<
-
-
-
- Proposal Meta Template
- |
-
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
-
- >
- ];
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+ >
+ ];
- "Proposal Template" [
- id="Proposal Template";
+ "Campaign Parameters" [
+ id="Campaign Parameters";
+ label=<
+
+
+
+ Campaign Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Category Parameters" [
+ id="Category Parameters";
+ label=<
+
+
+
+ Category Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Proposal Comment Presentation Template" [
+ id="Proposal Comment Presentation Template";
label=<
-
- Proposal Template
+ |
+ Proposal Comment Presentation Template
|
@@ -52,7 +89,7 @@ Relationships"
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ cb99b9bd-681a-49d8-9836-89107c02e8ef b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -78,17 +115,7 @@ Relationships"
-
-
-
- template |
- Proposal Meta Template |
-
-
- |
-
-
-
+ |
parameters |
@@ -103,73 +130,5 @@ Relationships"
];
- "Proposal" [
- id="Proposal";
- label=<
-
- >
- ];
-
-
- subgraph cluster_system_parameters {
- label = "System Parameters";
- color=blue
- penwidth=20
-
- "Brand Parameters" [
- id="Brand Parameters";
- label=<
-
-
-
- Brand Parameters
- |
-
-
-
- >
- ];
-
-
- "Campaign Parameters" [
- id="Campaign Parameters";
- label=<
-
-
-
- Campaign Parameters
- |
-
-
-
- >
- ];
-
-
- "Category Parameters" [
- id="Category Parameters";
- label=<
-
-
-
- Category Parameters
- |
-
-
-
- >
- ];
-
- }
-
- "Proposal Template":"template":e -> "Proposal Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal":"title":e -> "Proposal Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Comment Presentation Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_meta_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_form_template.dot
similarity index 88%
rename from docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_meta_template.dot
rename to docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_form_template.dot
index 9f51887bc3..4a4fe091ca 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_meta_template.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_form_template.dot
@@ -1,11 +1,11 @@
-digraph "Proposal Meta Template" {
+digraph "Proposal Form Template" {
rankdir="LR"
graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
labelloc="t"
- label="Proposal Meta Template
+ label="Proposal Form Template
Document Relationships"
fontcolor="#1d71b8"
fontsize=50
@@ -64,13 +64,13 @@ Document Relationships"
}
- "Proposal Meta Template" [
- id="Proposal Meta Template";
+ "Proposal Form Template" [
+ id="Proposal Form Template";
label=<
-
- Proposal Meta Template
+ |
+ Proposal Form Template
|
@@ -88,7 +88,7 @@ Document Relationships"
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -129,13 +129,13 @@ Document Relationships"
];
- "Proposal Template" [
- id="Proposal Template";
+ "Proposal" [
+ id="Proposal";
label=<
-
- Proposal Template
+ |
+ Proposal
|
@@ -144,6 +144,6 @@ Document Relationships"
];
- "Proposal Meta Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Template":"title":e -> "Proposal Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Proposal Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal":"title":e -> "Proposal Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/decision_parameters.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_presentation_template.dot
similarity index 86%
rename from docs/src/architecture/08_concepts/signed_doc/diagrams/decision_parameters.dot
rename to docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_presentation_template.dot
index ff41dcf0f6..e4d23f74a8 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/decision_parameters.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_presentation_template.dot
@@ -1,12 +1,12 @@
-digraph "Decision Parameters" {
+digraph "Proposal Presentation Template" {
rankdir="LR"
graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
labelloc="t"
- label="Decision Parameters Document
-Relationships"
+ label="Proposal Presentation Template
+Document Relationships"
fontcolor="#1d71b8"
fontsize=50
compound=true
@@ -64,13 +64,13 @@ Relationships"
}
- "Decision Parameters" [
- id="Decision Parameters";
+ "Proposal Presentation Template" [
+ id="Proposal Presentation Template";
label=<
-
- Decision Parameters
+ |
+ Proposal Presentation Template
|
@@ -78,7 +78,7 @@ Relationships"
content type |
- application/json |
+ application/schema+json |
@@ -88,7 +88,7 @@ Relationships"
type |
- 788ff4c6-d65a-451f-bb33-575fe056b411 |
+ cb99b9bd-681a-49d8-9836-89107c02e8ef 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
@@ -129,5 +129,5 @@ Relationships"
];
- "Decision Parameters":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Proposal Presentation Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination.dot
new file mode 100644
index 0000000000..bd83b20155
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination.dot
@@ -0,0 +1,175 @@
+digraph "Rep Nomination" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Rep Nomination Document
+Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Rep Profile" [
+ id="Rep Profile";
+ label=<
+
+
+
+ Rep Profile
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination Form Template" [
+ id="Rep Nomination Form Template";
+ label=<
+
+
+
+ Rep Nomination Form Template
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Parameters" [
+ id="Contest Parameters";
+ label=<
+
+
+
+ Contest Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination" [
+ id="Rep Nomination";
+ label=<
+
+
+
+ Rep Nomination
+ |
+
+
+
+
+
+ content type |
+ application/json |
+
+
+ |
+
+
+
+
+
+ type |
+ bf9abd97-5d1f-4429-8e80-740fea371a9c 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ ref |
+ Rep Profile |
+
+
+ |
+
+
+
+
+
+ template |
+ Rep Nomination Form Template |
+
+
+ |
+
+
+
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Contest Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Contest Delegation" [
+ id="Contest Delegation";
+ label=<
+
+
+
+ Contest Delegation
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination":"ref":e -> "Rep Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"template":e -> "Rep Nomination Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Contest Delegation":"title":e -> "Rep Nomination":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination_form_template.dot
new file mode 100644
index 0000000000..27e572ed62
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_nomination_form_template.dot
@@ -0,0 +1,113 @@
+digraph "Rep Nomination Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Rep Nomination Form Template
+Document Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ "Contest Parameters" [
+ id="Contest Parameters";
+ label=<
+
+
+
+ Contest Parameters
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination Form Template" [
+ id="Rep Nomination Form Template";
+ label=<
+
+
+
+ Rep Nomination Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f bf9abd97-5d1f-4429-8e80-740fea371a9c 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Contest Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination" [
+ id="Rep Nomination";
+ label=<
+
+
+
+ Rep Nomination
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Nomination Form Template":"parameters":e -> "Contest Parameters":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Nomination":"title":e -> "Rep Nomination Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile.dot
similarity index 61%
rename from docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_template.dot
rename to docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile.dot
index 0b8ef6a746..f7741a8b95 100644
--- a/docs/src/architecture/08_concepts/signed_doc/diagrams/proposal_comment_template.dot
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile.dot
@@ -1,25 +1,25 @@
-digraph "Proposal Comment Template" {
+digraph "Rep Profile" {
rankdir="LR"
graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
labelloc="t"
- label="Proposal Comment Template
-Document Relationships"
+ label="Rep Profile Document
+Relationships"
fontcolor="#1d71b8"
fontsize=50
compound=true
- "Proposal Comment Meta Template" [
- id="Proposal Comment Meta Template";
+ "Rep Profile Form Template" [
+ id="Rep Profile Form Template";
label=<
-
- Proposal Comment Meta Template
+ |
+ Rep Profile Form Template
|
@@ -28,13 +28,13 @@ Document Relationships"
];
- "Proposal Comment Template" [
- id="Proposal Comment Template";
+ "Rep Profile" [
+ id="Rep Profile";
label=<
-
- Proposal Comment Template
+ |
+ Rep Profile
|
@@ -42,7 +42,7 @@ Document Relationships"
content type |
- application/schema+json |
+ application/json |
@@ -52,7 +52,7 @@ Document Relationships"
type |
- 0ce8ab38-9258-4fbc-a62e-7faa6e58318f b679ded3-0e7c-41ba-89f8-da62a17898ea 7808d2ba-d511-40af-84e8-c0d1625fdfdc |
+ 0f2c86a2-ffda-40b0-ad38-23709e1c10b3 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
@@ -82,17 +82,27 @@ Document Relationships"
template |
- Proposal Comment Meta Template |
+ Rep Profile Form Template |
-
+ |
+
+
+ revocations |
+ Version Revocations |
+
+
+ |
+
+
+
parameters |
- Brand Parameters Campaign Parameters Category Parameters |
+ Brand Parameters |
|
@@ -103,13 +113,13 @@ Document Relationships"
];
- "Proposal Comment" [
- id="Proposal Comment";
+ "Rep Nomination" [
+ id="Rep Nomination";
label=<
-
- Proposal Comment
+ |
+ Rep Nomination
|
@@ -137,39 +147,9 @@ Document Relationships"
>
];
-
- "Campaign Parameters" [
- id="Campaign Parameters";
- label=<
-
-
-
- Campaign Parameters
- |
-
-
-
- >
- ];
-
-
- "Category Parameters" [
- id="Category Parameters";
- label=<
-
-
-
- Category Parameters
- |
-
-
-
- >
- ];
-
}
- "Proposal Comment Template":"template":e -> "Proposal Comment Meta Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
- "Proposal Comment Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
- "Proposal Comment":"title":e -> "Proposal Comment Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Profile":"template":e -> "Rep Profile Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+ "Rep Profile":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Nomination":"title":e -> "Rep Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
}
diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile_form_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile_form_template.dot
new file mode 100644
index 0000000000..b06843a2c6
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/rep_profile_form_template.dot
@@ -0,0 +1,119 @@
+digraph "Rep Profile Form Template" {
+ rankdir="LR"
+ graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"];
+ node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"];
+ edge [fontname="helvetica", fontsize="32", fontcolor="red", color="#29235c"];
+
+ labelloc="t"
+ label="Rep Profile Form Template
+Document Relationships"
+ fontcolor="#1d71b8"
+ fontsize=50
+ compound=true
+
+
+
+ subgraph cluster_system_parameters {
+ label = "System Parameters";
+ color=blue
+ penwidth=20
+
+ "Brand Parameters" [
+ id="Brand Parameters";
+ label=<
+
+
+
+ Brand Parameters
+ |
+
+
+
+ >
+ ];
+
+ }
+
+ "Rep Profile Form Template" [
+ id="Rep Profile Form Template";
+ label=<
+
+
+
+ Rep Profile Form Template
+ |
+
+
+
+
+
+ content type |
+ application/schema+json |
+
+
+ |
+
+
+
+
+
+ type |
+ 0ce8ab38-9258-4fbc-a62e-7faa6e58318f 0f2c86a2-ffda-40b0-ad38-23709e1c10b3 94579df1-a6dc-433b-a8e8-910c5dc2f0e3 |
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ ver |
+ Document Ver |
+
+
+ |
+
+
+
+
+
+ parameters |
+ Brand Parameters |
+
+
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Profile" [
+ id="Rep Profile";
+ label=<
+
+
+
+ Rep Profile
+ |
+
+
+
+ >
+ ];
+
+
+ "Rep Profile Form Template":"parameters":e -> "Brand Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"]
+ "Rep Profile":"title":e -> "Rep Profile Form Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"]
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md
index 6e74a9b972..9d24a1c94a 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md
@@ -2,7 +2,24 @@
## Description
-Parameters which define this brand within the system.
+Brand Parameters define the parameter data required for the
+system at the Brand level.
+
+Parameter Data includes things such as:
+
+* Functional parameters
+* Timeline data
+* Branded Content and Copy
+
+The content of the parameters is defined solely by the
+Brand Parameters Form Template.
+
+This allows parameters to vary based on individual system
+requirements over time.
+
+Functional Parameters are mapped using the (TBD Functional Parameters Map).
+
+The payload of a Brand is controlled by its template.
@@ -14,10 +31,7 @@ Parameters which define this brand within the system.
### Validation
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+No extra validation defined.
### Business Logic
@@ -49,7 +63,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `ebcabeeb-5bc5-4f95-91e8-cab8ca724172` |
+| Type | `60185874-7e13-407c-a06c-238ffe637ae6`, `ebcabeeb-5bc5-4f95-91e8-cab8ca724172` |
The document TYPE.
@@ -85,26 +99,96 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Brand Parameters Form Template](brand_parameters_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`collaborators`](../metadata.md#collaborators)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Collaborators Reference List](../metadata.md#collaborators-reference-list) |
+
+A list of collaborators who may also publish updates to versions of this document.
+This should include all parties who have not signed this document directly.
+
+Every subsequent version can amend the collaborators list.
+However, the initial Author can never be removed from being able to
+publish a new version of the document.
+
+#### [`collaborators`](../metadata.md#collaborators) Validation
+
+This list does not imply these collaborators have consented to collaborate, only that the author/s
+are permitting these potential collaborators to participate in the drafting and submission process.
+However, any document submission referencing a proposal MUST be signed by all collaborators in
+addition to the author.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
## Payload
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+Brand Parameters Document controlling the Brand
+within a Brand.
+
+Must be valid according to the schema contained within the
+[Document Reference](../metadata.md#document-reference) from the [`template`](../metadata.md#template) metadata.
## Signers
-The following user roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Registered
+* Brand Admin
New versions of this document may be published by:
* author
+* collaborators
## Copyright
@@ -112,8 +196,9 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-06-20 |
| Authors | Alex Pozhylenkov |
+| | Nathan Bogale |
| | Steven Johnson |
### Changelog
@@ -122,6 +207,10 @@ New versions of this document may be published by:
* First Published Version
+#### 0.02 (2025-06-20)
+
+* Generalized as another kind of form data document
+
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters_form_template.md
similarity index 65%
rename from docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md
rename to docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters_form_template.md
index 95e049ecf2..76e5c64df3 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters_form_template.md
@@ -1,13 +1,32 @@
-# Decision Parameters
+# Brand Parameters Form Template
## Description
-Parameters which define an individual voting event.
+A Brand Parameters Form Template defines both:
+
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
+
+A Brand Parameters Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Brand Parameters entry *SHOULD* use the hints when collecting
+data defined by the Brand Parameters Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Brand Parameters Presentation Template can be used to
+format the Brand Parameters data for presentation.
+
+The Brand Parameters Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Brand Parameters.
+
+The payload of a Brand Parameters is controlled by its template.
-```graphviz dot decision_parameters.dot.svg
-{{ include_file('./../diagrams/decision_parameters.dot', indent=4) }}
+```graphviz dot brand_parameters_form_template.dot.svg
+{{ include_file('./../diagrams/brand_parameters_form_template.dot', indent=4) }}
```
@@ -37,7 +56,7 @@ This section will be included and updated in future iterations.
## [COSE Header Parameters][RFC9052-HeaderParameters]
-* [content type](../spec.md#content-type) = `application/json`
+* [content type](../spec.md#content-type) = `application/schema+json`
* [content-encoding](../spec.md#content-encoding) = `[br]`
## Metadata
@@ -49,7 +68,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `788ff4c6-d65a-451f-bb33-575fe056b411` |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `60185874-7e13-407c-a06c-238ffe637ae6`, `ebcabeeb-5bc5-4f95-91e8-cab8ca724172` |
The document TYPE.
@@ -85,42 +104,23 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
-### [`parameters`](../metadata.md#parameters)
-
-
-| Parameter | Value |
-| --- | --- |
-| Required | yes |
-| Format | [Document Reference](../metadata.md#document-reference) |
-| Valid References | [Brand Parameters](brand_parameters.md) |
-| | [Campaign Parameters](campaign_parameters.md) |
-| | [Category Parameters](category_parameters.md) |
-
-A reference to the Parameters Document this document lies under.
-
-#### [`parameters`](../metadata.md#parameters) Validation
-
-In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
-
-* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
-
## Payload
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Brand Parameters Document.
## Signers
-The following user roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Registered
+* Brand Admin
New versions of this document may be published by:
@@ -132,7 +132,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
@@ -146,6 +146,11 @@ New versions of this document may be published by:
* Use generalized parameters.
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md
index 40b40909c1..2202e9b9ec 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md
@@ -2,7 +2,24 @@
## Description
-Parameters which define a Campaign within a Brand in the system.
+Campaign Parameters define the parameter data required for the
+system at the Campaign level.
+
+Parameter Data includes things such as:
+
+* Functional parameters
+* Timeline data
+* Branded Content and Copy
+
+The content of the parameters is defined solely by the
+Campaign Parameters Form Template.
+
+This allows parameters to vary based on individual system
+requirements over time.
+
+Functional Parameters are mapped using the (TBD Functional Parameters Map).
+
+The payload of a Campaign is controlled by its template.
@@ -14,10 +31,8 @@ Parameters which define a Campaign within a Brand in the system.
### Validation
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+The Campaign Parameters Document *MUST* be linked through [`parameters`](../metadata.md#parameters) to
+its Brand Parameters Document.
### Business Logic
@@ -49,7 +64,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `5ef32d5d-f240-462c-a7a4-ba4af221fa23` |
+| Type | `60185874-7e13-407c-a06c-238ffe637ae6`, `5ef32d5d-f240-462c-a7a4-ba4af221fa23` |
The document TYPE.
@@ -85,10 +100,78 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Campaign Parameters Form Template](campaign_parameters_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`collaborators`](../metadata.md#collaborators)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Collaborators Reference List](../metadata.md#collaborators-reference-list) |
+
+A list of collaborators who may also publish updates to versions of this document.
+This should include all parties who have not signed this document directly.
+
+Every subsequent version can amend the collaborators list.
+However, the initial Author can never be removed from being able to
+publish a new version of the document.
+
+#### [`collaborators`](../metadata.md#collaborators) Validation
+
+This list does not imply these collaborators have consented to collaborate, only that the author/s
+are permitting these potential collaborators to participate in the drafting and submission process.
+However, any document submission referencing a proposal MUST be signed by all collaborators in
+addition to the author.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
### [`parameters`](../metadata.md#parameters)
@@ -105,24 +188,36 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
## Payload
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+Campaign Parameters Document controlling the Campaign
+within a Brand.
+
+Must be valid according to the schema contained within the
+[Document Reference](../metadata.md#document-reference) from the [`template`](../metadata.md#template) metadata.
## Signers
-The following user roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Registered
+* Brand Admin
New versions of this document may be published by:
* author
+* collaborators
## Copyright
@@ -130,8 +225,9 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-06-20 |
| Authors | Alex Pozhylenkov |
+| | Nathan Bogale |
| | Steven Johnson |
### Changelog
@@ -140,9 +236,9 @@ New versions of this document may be published by:
* First Published Version
-#### 0.03 (2025-05-05)
+#### 0.02 (2025-06-20)
-* Use generalized parameters.
+* Generalized as another kind of form data document
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters_form_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters_form_template.md
new file mode 100644
index 0000000000..5f2874efd6
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters_form_template.md
@@ -0,0 +1,156 @@
+# Campaign Parameters Form Template
+
+## Description
+
+A Campaign Parameters Form Template defines both:
+
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
+
+A Campaign Parameters Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Campaign Parameters entry *SHOULD* use the hints when collecting
+data defined by the Campaign Parameters Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Campaign Parameters Presentation Template can be used to
+format the Campaign Parameters data for presentation.
+
+The Campaign Parameters Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Campaign Parameters.
+
+The payload of a Campaign Parameters is controlled by its template.
+
+
+
+```graphviz dot campaign_parameters_form_template.dot.svg
+{{ include_file('./../diagrams/campaign_parameters_form_template.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/schema+json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `60185874-7e13-407c-a06c-238ffe637ae6`, `5ef32d5d-f240-462c-a7a4-ba4af221fa23` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+## Payload
+
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Campaign Parameters Document.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-05-30 |
+| Authors | Alex Pozhylenkov |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-04-04)
+
+* First Published Version
+
+#### 0.03 (2025-05-05)
+
+* Use generalized parameters.
+
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md
index 07f5156139..c5ece3413a 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md
@@ -2,7 +2,24 @@
## Description
-Parameters which define a Category withing a Campaign under a Brand in the system.
+Category Parameters define the parameter data required for the
+system at the Category level.
+
+Parameter Data includes things such as:
+
+* Functional parameters
+* Timeline data
+* Branded Content and Copy
+
+The content of the parameters is defined solely by the
+Category Parameters Form Template.
+
+This allows parameters to vary based on individual system
+requirements over time.
+
+Functional Parameters are mapped using the (TBD Functional Parameters Map).
+
+The payload of a Category is controlled by its template.
@@ -14,10 +31,8 @@ Parameters which define a Category withing a Campaign under a Brand in the syste
### Validation
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+The Category Parameters Document *MUST* be linked through [`parameters`](../metadata.md#parameters) to
+its Campaign Parameters Document.
### Business Logic
@@ -49,7 +64,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `818938c3-3139-4daa-afe6-974c78488e95` |
+| Type | `60185874-7e13-407c-a06c-238ffe637ae6`, `818938c3-3139-4daa-afe6-974c78488e95` |
The document TYPE.
@@ -85,10 +100,78 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Category Parameters Form Template](category_parameters_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`collaborators`](../metadata.md#collaborators)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Collaborators Reference List](../metadata.md#collaborators-reference-list) |
+
+A list of collaborators who may also publish updates to versions of this document.
+This should include all parties who have not signed this document directly.
+
+Every subsequent version can amend the collaborators list.
+However, the initial Author can never be removed from being able to
+publish a new version of the document.
+
+#### [`collaborators`](../metadata.md#collaborators) Validation
+
+This list does not imply these collaborators have consented to collaborate, only that the author/s
+are permitting these potential collaborators to participate in the drafting and submission process.
+However, any document submission referencing a proposal MUST be signed by all collaborators in
+addition to the author.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
### [`parameters`](../metadata.md#parameters)
@@ -105,24 +188,36 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
## Payload
-This specification outlines the required definitions for the current features.
-The document will be incrementally improved in future iterations as more functionality
-and features are added.
-This section will be included and updated in future iterations.
+Category Parameters Document controlling the Category
+within a Campaign.
+
+Must be valid according to the schema contained within the
+[Document Reference](../metadata.md#document-reference) from the [`template`](../metadata.md#template) metadata.
## Signers
-The following user roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Registered
+* Brand Admin
New versions of this document may be published by:
* author
+* collaborators
## Copyright
@@ -130,8 +225,9 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-06-20 |
| Authors | Alex Pozhylenkov |
+| | Nathan Bogale |
| | Steven Johnson |
### Changelog
@@ -140,9 +236,9 @@ New versions of this document may be published by:
* First Published Version
-#### 0.03 (2025-05-05)
+#### 0.02 (2025-06-20)
-* Use generalized parameters.
+* Generalized as another kind of form data document
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters_form_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters_form_template.md
new file mode 100644
index 0000000000..03f61374d8
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters_form_template.md
@@ -0,0 +1,156 @@
+# Category Parameters Form Template
+
+## Description
+
+A Category Parameters Form Template defines both:
+
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
+
+A Category Parameters Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Category Parameters entry *SHOULD* use the hints when collecting
+data defined by the Category Parameters Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Category Parameters Presentation Template can be used to
+format the Category Parameters data for presentation.
+
+The Category Parameters Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Category Parameters.
+
+The payload of a Category Parameters is controlled by its template.
+
+
+
+```graphviz dot category_parameters_form_template.dot.svg
+{{ include_file('./../diagrams/category_parameters_form_template.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/schema+json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `60185874-7e13-407c-a06c-238ffe637ae6`, `818938c3-3139-4daa-afe6-974c78488e95` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+## Payload
+
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Category Parameters Document.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-05-30 |
+| Authors | Alex Pozhylenkov |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-04-04)
+
+* First Published Version
+
+#### 0.03 (2025-05-05)
+
+* Use generalized parameters.
+
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/comment_moderation_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/comment_moderation_action.md
index 5b9907ca1f..ed9a0493f9 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/comment_moderation_action.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/comment_moderation_action.md
@@ -85,6 +85,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -107,7 +109,7 @@ Some documents allow multiple references, and they are documented as required.
The document reference serves two purposes:
1. It ensures that the document referenced by an ID/Version is not substituted.
- In other words, that the document intended to be referenced, is actually referenced.
+ In other words, that the document intended to be referenced, is actually referenced.
2. It Allows the document to be unambiguously located in decentralized storage systems.
There can be any number of Document Locations in any reference.
@@ -139,7 +141,7 @@ This section will be included and updated in future iterations.
## Signers
-The following user roles may sign documents of this type:
+The following User roles may sign documents of this type:
* Registered
@@ -153,7 +155,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/contest_delegation.md b/docs/src/architecture/08_concepts/signed_doc/docs/contest_delegation.md
new file mode 100644
index 0000000000..89ea30af96
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/contest_delegation.md
@@ -0,0 +1,229 @@
+# Contest Delegation
+
+## Description
+
+Delegation by a Registered User to a Representative for
+a contest.
+
+This delegation allows votes cast by the Representative
+to use the voting power of the delegating User, in addition
+to their own personal voting power and that of all other Users
+who delegate to the same Representative.
+
+Delegation is for a specific Contest.
+Multiple Delegations must be published if there are multiple
+Contests within a Brand/Campaign or Category.
+
+This is because different Contests may have different rules.
+And not all Representatives will choose to nominate
+for every Contest.
+
+
+
+```graphviz dot contest_delegation.dot.svg
+{{ include_file('./../diagrams/contest_delegation.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+* The [`parameters`](../metadata.md#parameters) metadata *MUST* point to the same Contest as the
+ Nomination of the Representative.
+* The 'ref' metadata field MUST point to a valid 'Representative Nomination'.
+* The payload MUST be nil.
+
+A Representative *MUST* Delegate to their latest Nomination for a Category,
+otherwise their Nomination is invalid.
+
+This is because Delegation points to a *SPECIFIC* Nomination, and it
+*MUST* be the latest for the Representative on the Contest.
+As the Nomination contains information that the User relies on
+when choosing to delegate, changing that information could have a
+real and detrimental result in the Delegation choice.
+Therefore, for a Delegation to be valid, it *MUST* point to the
+latest Nomination for a Representative.
+
+### Business Logic
+
+#### Front End
+
+* Allows a voter to select a Representative from a list of eligible candidates for a category.
+* The voter signs this document to confirm their delegation choice.
+
+#### Back End
+
+* Verifies that the voter and Representative are valid and registered for the category.
+* Records the delegation of voting power from the voter to the Representative.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+No Headers are defined for this document.
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `764f17fb-cc50-4979-b14a-b213dbac5994`, `788ff4c6-d65a-451f-bb33-575fe056b411` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`ref`](../metadata.md#ref)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Rep Nomination](rep_nomination.md) |
+
+Reference to a Linked Document or Documents.
+This is the primary hierarchical reference to a related document.
+
+If a reference is defined as required, there must be at least 1 reference specified.
+Some documents allow multiple references, and they are documented as required.
+
+The document reference serves two purposes:
+
+1. It ensures that the document referenced by an ID/Version is not substituted.
+ In other words, that the document intended to be referenced, is actually referenced.
+2. It Allows the document to be unambiguously located in decentralized storage systems.
+
+There can be any number of Document Locations in any reference.
+The currently defined locations are:
+
+* `cid` : A [CBOR Encoded IPLD Content Identifier][CBOR-TAG-42] ( AKA an [IPFS CID][IPFS-CID] ).
+* Others may be added when further storage mechanisms are defined.
+
+The document location does not guarantee that the document is actually stored.
+It only defines that if it were stored, this is the identifier
+that is required to retrieve it.
+Therefore it is required that Document References
+are unique and reproducible, given a documents contents.
+
+#### [`ref`](../metadata.md#ref) Validation
+
+The following must be true for a valid reference:
+
+* The Referenced Document **MUST** Exist
+* Every value in the `document_locator` must consistently reference the exact same document.
+* The `document_id` and `document_ver` **MUST** match the values in the referenced document.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Contest Parameters](contest_parameters.md) |
+| Linked Reference Metadata | [`ref`](#ref) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+* The Document referenced by [`ref`](../metadata.md#ref)
+ * MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
+ * MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
+
+## Payload
+
+A minimal payload indicating the intended status of the delegation.
+ 'active' creates or affirms the delegation.
+ 'revoked' withdraws the delegation.
+
+This document has no payload.
+It must be encoded as a [CBOR][RFC8949] `null (0xf6)`.
+
+## Signers
+
+The following User roles may sign documents of this type:
+
+* Registered
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-06-19 |
+| Authors | Alex Pozhylenkov |
+| | Neil McAuliffe |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-06-19)
+
+* First Published Version
+
+[CBOR-TAG-42]: https://github.com/ipld/cid-cbor/
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[IPFS-CID]: https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
+[RFC8949]: https://www.rfc-editor.org/rfc/rfc8949.html
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters.md
new file mode 100644
index 0000000000..ef50603926
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters.md
@@ -0,0 +1,247 @@
+# Contest Parameters
+
+## Description
+
+Contest Parameters define the parameter data required for the
+system at the Contest level.
+
+Parameter Data includes things such as:
+
+* Functional parameters
+* Timeline data
+* Branded Content and Copy
+
+The content of the parameters is defined solely by the
+Contest Parameters Form Template.
+
+This allows parameters to vary based on individual system
+requirements over time.
+
+Functional Parameters are mapped using the (TBD Functional Parameters Map).
+
+The payload of a Contest is controlled by its template.
+
+
+
+```graphviz dot contest_parameters.dot.svg
+{{ include_file('./../diagrams/contest_parameters.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+The Contest Parameters Document *MUST* be linked through [`parameters`](../metadata.md#parameters) to
+its Brand/Campaign/Category Parameters Document.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `60185874-7e13-407c-a06c-238ffe637ae6`, `788ff4c6-d65a-451f-bb33-575fe056b411` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Contest Parameters Form Template](contest_parameters_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`collaborators`](../metadata.md#collaborators)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Collaborators Reference List](../metadata.md#collaborators-reference-list) |
+
+A list of collaborators who may also publish updates to versions of this document.
+This should include all parties who have not signed this document directly.
+
+Every subsequent version can amend the collaborators list.
+However, the initial Author can never be removed from being able to
+publish a new version of the document.
+
+#### [`collaborators`](../metadata.md#collaborators) Validation
+
+This list does not imply these collaborators have consented to collaborate, only that the author/s
+are permitting these potential collaborators to participate in the drafting and submission process.
+However, any document submission referencing a proposal MUST be signed by all collaborators in
+addition to the author.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Brand Parameters](brand_parameters.md) |
+| | [Campaign Parameters](campaign_parameters.md) |
+| | [Category Parameters](category_parameters.md) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+## Payload
+
+Contest Parameters Document controlling the Contest
+within a Brand/Campaign/Category.
+
+Must be valid according to the schema contained within the
+[Document Reference](../metadata.md#document-reference) from the [`template`](../metadata.md#template) metadata.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+
+New versions of this document may be published by:
+
+* author
+* collaborators
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-06-20 |
+| Authors | Alex Pozhylenkov |
+| | Nathan Bogale |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-04-04)
+
+* First Published Version
+
+#### 0.02 (2025-06-20)
+
+* Generalized as another kind of form data document
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters_form_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters_form_template.md
new file mode 100644
index 0000000000..2f6c342231
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/contest_parameters_form_template.md
@@ -0,0 +1,156 @@
+# Contest Parameters Form Template
+
+## Description
+
+A Contest Parameters Form Template defines both:
+
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
+
+A Contest Parameters Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Contest Parameters entry *SHOULD* use the hints when collecting
+data defined by the Contest Parameters Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Contest Parameters Presentation Template can be used to
+format the Contest Parameters data for presentation.
+
+The Contest Parameters Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Contest Parameters.
+
+The payload of a Contest Parameters is controlled by its template.
+
+
+
+```graphviz dot contest_parameters_form_template.dot.svg
+{{ include_file('./../diagrams/contest_parameters_form_template.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/schema+json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `60185874-7e13-407c-a06c-238ffe637ae6`, `788ff4c6-d65a-451f-bb33-575fe056b411` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+## Payload
+
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Contest Parameters Document.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-05-30 |
+| Authors | Alex Pozhylenkov |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-04-04)
+
+* First Published Version
+
+#### 0.03 (2025-05-05)
+
+* Use generalized parameters.
+
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md
index c11ad6354e..964e4120b3 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md
@@ -108,6 +108,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -119,7 +121,7 @@ The document version must always be >= the document ID.
| --- | --- |
| Required | yes |
| Format | [Document Reference](../metadata.md#document-reference) |
-| Valid References | [Proposal Template](proposal_template.md) |
+| Valid References | [Proposal Form Template](proposal_form_template.md) |
Reference to the template used to create and/or validate this document.
@@ -197,7 +199,18 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
* The Document referenced by [`template`](../metadata.md#template)
* MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
* MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
@@ -211,7 +224,7 @@ Must be valid according to the schema contained within the
## Signers
-The following user roles may sign documents of this type:
+The following User roles may sign documents of this type:
* Proposer
@@ -226,7 +239,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md
index 212b50e7b4..61a0e72467 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md
@@ -92,6 +92,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -114,7 +116,7 @@ Some documents allow multiple references, and they are documented as required.
The document reference serves two purposes:
1. It ensures that the document referenced by an ID/Version is not substituted.
- In other words, that the document intended to be referenced, is actually referenced.
+ In other words, that the document intended to be referenced, is actually referenced.
2. It Allows the document to be unambiguously located in decentralized storage systems.
There can be any number of Document Locations in any reference.
@@ -144,7 +146,7 @@ The following must be true for a valid reference:
| --- | --- |
| Required | yes |
| Format | [Document Reference](../metadata.md#document-reference) |
-| Valid References | [Proposal Comment Template](proposal_comment_template.md) |
+| Valid References | [Proposal Comment Form Template](proposal_comment_form_template.md) |
Reference to the template used to create and/or validate this document.
@@ -233,10 +235,22 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
* The Document referenced by [`ref`](../metadata.md#ref)
* MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
* MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
+
* The Document referenced by [`template`](../metadata.md#template)
* MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
* MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
@@ -247,7 +261,7 @@ In addition to the validation performed for [Document Reference](../metadata.md#
## Signers
-The following user roles may sign documents of this type:
+The following User roles may sign documents of this type:
* Registered
@@ -261,7 +275,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_form_template.md
similarity index 68%
rename from docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md
rename to docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_form_template.md
index 91c7b241f9..944ba4e4f4 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_form_template.md
@@ -1,21 +1,32 @@
-# Proposal Comment Template
+# Proposal Comment Form Template
## Description
-## Proposal Comment Template Document
+A Proposal Comment Form Template defines both:
-A Proposal Comment Template defines the allowed payload contents of a
-linked proposal comment.
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
-Proposal comments themselves are intentionally general, however they may be
-linked to a brand/campaign or category via the template used by the proposal.
+A Proposal Comment Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
-The payload of a proposal comment is controlled by its template.
+Proposal Comment entry *SHOULD* use the hints when collecting
+data defined by the Proposal Comment Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Proposal Comment Presentation Template can be used to
+format the Proposal Comment data for presentation.
+
+The Proposal Comment Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Proposal Comment.
+
+The payload of a Proposal Comment is controlled by its template.
-```graphviz dot proposal_comment_template.dot.svg
-{{ include_file('./../diagrams/proposal_comment_template.dot', indent=4) }}
+```graphviz dot proposal_comment_form_template.dot.svg
+{{ include_file('./../diagrams/proposal_comment_form_template.dot', indent=4) }}
```
@@ -93,26 +104,12 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
-### [`template`](../metadata.md#template)
-
-
-| Parameter | Value |
-| --- | --- |
-| Required | optional |
-| Format | [Document Reference](../metadata.md#document-reference) |
-| Valid References | [Proposal Comment Meta Template](proposal_comment_meta_template.md) |
-
-Reference to the template used to create and/or validate this document.
-
-#### [`template`](../metadata.md#template) Validation
-
-In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
-The document payload is not valid if it does not validate completely against the referenced template.
-
### [`parameters`](../metadata.md#parameters)
@@ -131,18 +128,29 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
## Payload
-[JSON Schema] document which defines the content of the Proposal Comments.
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Proposal Comment Document.
## Signers
-The following admin roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
* Brand Admin
-* Campaign Admin
New versions of this document may be published by:
@@ -154,7 +162,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
@@ -168,7 +176,11 @@ New versions of this document may be published by:
* Use generalized parameters.
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
-[JSON Schema]: https://json-schema.org/draft-07
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_presentation_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_presentation_template.md
new file mode 100644
index 0000000000..e39ad021ee
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_presentation_template.md
@@ -0,0 +1,182 @@
+# Proposal Comment Presentation Template
+
+## Description
+
+A Proposal Comment Presentation Template defines how the data
+captured by the Proposal Comment Form Template is to be displayed.
+
+Multiple Proposal Comment Presentation Templates can exist for the
+same Proposal Comment Form Template.
+Each can be used to display the form data under different
+circumstances.
+
+Proposal Comment Presentation Templates can reference any data contained
+in the Proposal Comment Document, as well as any documents linked by:
+
+* [`ref`](../metadata.md#ref)
+* [`reply`](../metadata.md#reply)
+* [`parameters`](../metadata.md#parameters)
+
+The presentation of the payload of a Proposal Comment is controlled by
+its Proposal Comment Presentation Template/s.
+
+
+
+```graphviz dot proposal_comment_presentation_template.dot.svg
+{{ include_file('./../diagrams/proposal_comment_presentation_template.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/schema+json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `cb99b9bd-681a-49d8-9836-89107c02e8ef`, `b679ded3-0e7c-41ba-89f8-da62a17898ea`, `7808d2ba-d511-40af-84e8-c0d1625fdfdc` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Brand Parameters](brand_parameters.md) |
+| | [Campaign Parameters](campaign_parameters.md) |
+| | [Category Parameters](category_parameters.md) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+## Payload
+
+TBD.
+But roughly, will be:
+
+1. A way to identify where the presentation template is intended to be used.
+2. Optional [CSS] to control the presentation.
+3. A [Handlebars] templated [HTML][HTML5] or [Markdown][CommonMark] file data which defines the presentation.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+* Campaign Admin
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-05-30 |
+| Authors | Alex Pozhylenkov |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.04 (2025-05-05)
+
+* First Version.
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[Handlebars]: https://handlebarsjs.com/
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[CommonMark]: https://spec.commonmark.org/0.31.2/
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
+[HTML5]: https://html.spec.whatwg.org/multipage/syntax.html#syntax
+[CSS]: https://www.w3.org/Style/CSS/
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_form_template.md
similarity index 69%
rename from docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md
rename to docs/src/architecture/08_concepts/signed_doc/docs/proposal_form_template.md
index b01b6eb41c..20b266c651 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_form_template.md
@@ -1,21 +1,32 @@
-# Proposal Template
+# Proposal Form Template
## Description
-## Proposal Template Document
+A Proposal Form Template defines both:
-A Proposal Template defines the allowed payload contents of a
-linked proposal.
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
-Proposals themselves are intentionally general, however they may be
-linked to a brand/campaign or category via the template used by the proposal.
+A Proposal Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
-The payload of a proposal is controlled by its template.
+Proposal entry *SHOULD* use the hints when collecting
+data defined by the Proposal Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Proposal Presentation Template can be used to
+format the Proposal data for presentation.
+
+The Proposal Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Proposal.
+
+The payload of a Proposal is controlled by its template.
-```graphviz dot proposal_template.dot.svg
-{{ include_file('./../diagrams/proposal_template.dot', indent=4) }}
+```graphviz dot proposal_form_template.dot.svg
+{{ include_file('./../diagrams/proposal_form_template.dot', indent=4) }}
```
@@ -93,26 +104,12 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
-### [`template`](../metadata.md#template)
-
-
-| Parameter | Value |
-| --- | --- |
-| Required | optional |
-| Format | [Document Reference](../metadata.md#document-reference) |
-| Valid References | [Proposal Meta Template](proposal_meta_template.md) |
-
-Reference to the template used to create and/or validate this document.
-
-#### [`template`](../metadata.md#template) Validation
-
-In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
-The document payload is not valid if it does not validate completely against the referenced template.
-
### [`parameters`](../metadata.md#parameters)
@@ -123,7 +120,6 @@ The document payload is not valid if it does not validate completely against the
| Valid References | [Brand Parameters](brand_parameters.md) |
| | [Campaign Parameters](campaign_parameters.md) |
| | [Category Parameters](category_parameters.md) |
-| Linked Reference Metadata | [`template`](#template) |
A reference to the Parameters Document this document lies under.
@@ -132,21 +128,29 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
-* The Document referenced by [`template`](../metadata.md#template)
- * MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
- * MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
## Payload
-[JSON Schema] document which defines the valid contents of a proposal document.
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Proposal Document.
## Signers
-The following admin roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
* Brand Admin
-* Campaign Admin
New versions of this document may be published by:
@@ -158,7 +162,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
@@ -172,7 +176,11 @@ New versions of this document may be published by:
* Use generalized parameters.
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
-[JSON Schema]: https://json-schema.org/draft-07
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md
index b8236d4597..47ced57cfc 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md
@@ -85,6 +85,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -139,7 +141,7 @@ This section will be included and updated in future iterations.
## Signers
-The following user roles may sign documents of this type:
+The following User roles may sign documents of this type:
* Registered
@@ -153,7 +155,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_presentation_template.md
similarity index 65%
rename from docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md
rename to docs/src/architecture/08_concepts/signed_doc/docs/proposal_presentation_template.md
index 305e9d497f..7080b8204b 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_presentation_template.md
@@ -1,18 +1,29 @@
-# Proposal Comment Meta Template
+# Proposal Presentation Template
## Description
-## Proposal Comment Meta Template Document
+A Proposal Presentation Template defines how the data
+captured by the Proposal Form Template is to be displayed.
-A Proposal Comment Meta Template is used to enforce functional requirements
-are met in any Proposal Comment Template.
+Multiple Proposal Presentation Templates can exist for the
+same Proposal Form Template.
+Each can be used to display the form data under different
+circumstances.
-The payload of a proposal comment template is controlled by its meta template.
+Proposal Presentation Templates can reference any data contained
+in the Proposal Document, as well as any documents linked by:
+
+* [`ref`](../metadata.md#ref)
+* [`reply`](../metadata.md#reply)
+* [`parameters`](../metadata.md#parameters)
+
+The presentation of the payload of a Proposal is controlled by
+its Proposal Presentation Template/s.
-```graphviz dot proposal_comment_meta_template.dot.svg
-{{ include_file('./../diagrams/proposal_comment_meta_template.dot', indent=4) }}
+```graphviz dot proposal_presentation_template.dot.svg
+{{ include_file('./../diagrams/proposal_presentation_template.dot', indent=4) }}
```
@@ -54,7 +65,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `b679ded3-0e7c-41ba-89f8-da62a17898ea`, `7808d2ba-d511-40af-84e8-c0d1625fdfdc` |
+| Type | `cb99b9bd-681a-49d8-9836-89107c02e8ef`, `7808d2ba-d511-40af-84e8-c0d1625fdfdc` |
The document TYPE.
@@ -90,6 +101,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -112,24 +125,33 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
-## Payload
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
-[JSON Schema] document which ensures the minimum required functional requirements
-of the Proposal Comment Template are met.
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
-This ensures that payloads can be reliably interpreted by business logic processes,
-while allowing for flexibility to capture extended information.
+## Payload
+
+TBD.
+But roughly, will be:
-Must be a valid according to .
+1. A way to identify where the presentation template is intended to be used.
+2. Optional [CSS] to control the presentation.
+3. A [Handlebars] templated [HTML][HTML5] or [Markdown][CommonMark] file data which defines the presentation.
## Signers
-The following admin roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Root Admin
* Brand Admin
+* Campaign Admin
New versions of this document may be published by:
@@ -141,21 +163,20 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
### Changelog
-#### 0.01 (2025-04-04)
-
-* First Published Version
-
-#### 0.03 (2025-05-05)
+#### 0.04 (2025-05-05)
-* Use generalized parameters.
+* First Version.
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
-[JSON Schema]: https://json-schema.org/draft-07
+[Handlebars]: https://handlebarsjs.com/
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[CommonMark]: https://spec.commonmark.org/0.31.2/
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
+[HTML5]: https://html.spec.whatwg.org/multipage/syntax.html#syntax
+[CSS]: https://www.w3.org/Style/CSS/
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md
index 68d7f89c2e..b512a5e41c 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md
@@ -2,7 +2,7 @@
## Description
-## Proposal Submission Action
+Proposal Submission Action
A Proposal Submission Action is a document which can attempt to either submit a
particular version of a proposal into a campaign, or withdraw it.
@@ -116,6 +116,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -139,7 +141,7 @@ Some documents allow multiple references, and they are documented as required.
The document reference serves two purposes:
1. It ensures that the document referenced by an ID/Version is not substituted.
- In other words, that the document intended to be referenced, is actually referenced.
+ In other words, that the document intended to be referenced, is actually referenced.
2. It Allows the document to be unambiguously located in decentralized storage systems.
There can be any number of Document Locations in any reference.
@@ -181,7 +183,18 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
* The Document referenced by [`ref`](../metadata.md#ref)
* MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
* MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
@@ -196,56 +209,113 @@ States:
* `final` : All collaborators must publish a `final` status for the proposal to be `final`.
* `draft` : Reverses the previous `final` state for a signer and accepts collaborator status to a document.
* `hide` : Requests the proposal be hidden (not final, but a hidden draft).
- `hide` is only actioned if sent by the author,
+ `hide` is only actioned if sent by the author,
for a collaborator it identified that they do not wish to be listed as a `collaborator`.
-Schema :
-
-```json
-{
- "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json",
- "$schema": "http://json-schema.org/draft-07/schema#",
- "additionalProperties": false,
- "definitions": {
- "action": {
- "description": "The action being performed on the Proposal.",
- "enum": [
- "final",
- "draft",
- "hide"
+### Schema
+
+
+??? abstract
+
+ The kind of action is controlled by this payload.
+ The Payload is a [JSON][RFC8259] Document, and must conform to this schema.
+
+ States:
+
+ * `final` : All collaborators must publish a `final` status for the proposal to be `final`.
+ * `draft` : Reverses the previous `final` state for a signer and accepts collaborator status to a document.
+ * `hide` : Requests the proposal be hidden (not final, but a hidden draft).
+ `hide` is only actioned if sent by the author,
+ for a collaborator it identified that they do not wish to be listed as a `collaborator`.
+
+ ```json
+ {
+ "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "additionalProperties": false,
+ "definitions": {
+ "action": {
+ "description": "The action being performed on the Proposal.",
+ "enum": [
+ "final",
+ "draft",
+ "hide"
+ ],
+ "type": "string"
+ }
+ },
+ "description": "Structure of the payload of a Proposal Submission Action.",
+ "maintainers": [
+ {
+ "name": "Catalyst Team",
+ "url": "https://projectcatalyst.io/"
+ }
],
- "type": "string"
+ "properties": {
+ "action": {
+ "$ref": "#/definitions/action"
+ }
+ },
+ "required": [
+ "action"
+ ],
+ "title": "Proposal Submission Action Payload Schema",
+ "type": "object",
+ "x-changelog": {
+ "2025-03-01": [
+ "First Version Created."
+ ]
+ }
+ }
+ ```
+
+
+
+### Examples
+
+??? example "Example: Final Proposal Submission"
+
+ This document indicates the linked proposal is final and requested to proceed for further consideration.
+
+ ```json
+ {
+ "action": "final"
}
- },
- "description": "Structure of the payload of a Proposal Submission Action.",
- "maintainers": [
+ ```
+
+
+
+??? example "Example: Draft Proposal Submission"
+
+ This document indicates the linked proposal is no longer final and should not proceed for further consideration.
+ It is also used by collaborators to accept that they are a collaborator on a document.
+
+ ```json
{
- "name": "Catalyst Team",
- "url": "https://projectcatalyst.io/"
+ "action": "draft"
}
- ],
- "properties": {
- "action": {
- "$ref": "#/definitions/action"
+ ```
+
+
+
+??? example "Example: Hidden Proposal Submission"
+
+ If submitted by the proposal author the document is hidden, it is still public but not shown as
+ a proposal being drafted.
+ If submitted by a collaborator, that collaborator is declaring they do not wish to be listed as
+ a collaborator on the proposal.
+
+ ```json
+ {
+ "action": "hide"
}
- },
- "required": [
- "action"
- ],
- "title": "Proposal Submission Action Payload Schema",
- "type": "object",
- "x-changelog": {
- "2025-03-01": [
- "First Version Created."
- ]
- }
-}
-```
-
+ ```
+
+
## Signers
-The following user roles may sign documents of this type:
+The following User roles may sign documents of this type:
* Proposer
@@ -260,7 +330,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination.md b/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination.md
new file mode 100644
index 0000000000..08b14f1773
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination.md
@@ -0,0 +1,296 @@
+# Rep Nomination
+
+## Description
+
+A Representative Nomination Document is created to opt
+in as a Representative Voter for a specific Contest on a Brand/Campaign or Category.
+
+This Document is a kind of `Profile` that is primarily used to
+help justify the Representatives Nomination to prospective delegators.
+
+The user must have registered as a Representative.
+The presence of this document signifies the user's intent to participate in that
+contest as a Representative.
+
+The document's structure is defined by the associated
+Rep Nomination Form Template.
+This allows an Admin to specify contest-specific requirements.
+
+The Representative can retract their nomination by using the `revoke` metadata to
+revoke this Nomination document.
+
+It is an extension of all other profiles attached to the same Catalyst ID.
+
+Profiles themselves are intentionally general, however they may be
+linked to a Brand/Campaign/Category via the template used by the profile.
+
+The payload of a profile is controlled by its template.
+
+
+
+```graphviz dot rep_nomination.dot.svg
+{{ include_file('./../diagrams/rep_nomination.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+* The signer MUST be a registered 'Representative'.
+* The 'ref' metadata field MUST point to a valid 'Representative Profile' document.
+* The 'parameters' metadata field MUST point to a valid 'Contest Parameters' document.
+* The 'template' metadata field MUST point to a valid 'Representative Nomination Form Template' document.
+* The payload MUST be valid against the [JSON schema][JSON Schema-2020-12] defined in the referenced template.
+* Other rules may apply as defined by the Contest or other parameters which can
+ control who may validly nominate as a representative in a Contest.
+
+No Nomination is valid unless the latest Contest Delegation of the Delegate
+refers to their own Nomination.
+This requires that Nominating is a two step process:
+
+1. Post the Nomination Document.
+2. Post a Contest Delegation delegating to the new Nomination Document.
+
+Updating the Nomination Document will invalidate all Nominations to the
+Representative.
+
+This is because Delegation points to a *SPECIFIC* Nomination, and it
+*MUST* be the latest for the Representative on the Contest.
+As the Nomination contains information that the User relies on
+when choosing to delegate, changing that information could have a
+real and detrimental result in the Delegation choice.
+Therefore, for a Delegation to be valid, it *MUST* point to the
+latest Nomination for a Representative.
+
+### Business Logic
+
+#### Front End
+
+* Allows a Representative to create or update their profile for a category.
+* The Representative sets their status to 'active' to be discoverable for delegation.
+* The Representative `revokes` the Nomination to signal they are no longer
+ participating in the category.
+* Nominations are not valid if the latest Delegation by the Representative does NOT
+ reference their latest Nomination.
+
+#### Back End
+
+* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.
+* The system will only consider Representatives as having valid Nominations if:
+ * Their latest Nomination in a Contest is not Revoked.
+ * Their latest Delegation in a Contest references their latest Nomination.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `bf9abd97-5d1f-4429-8e80-740fea371a9c`, `94579df1-a6dc-433b-a8e8-910c5dc2f0e3` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`ref`](../metadata.md#ref)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Rep Profile](rep_profile.md) |
+
+Reference to a Linked Document or Documents.
+This is the primary hierarchical reference to a related document.
+
+If a reference is defined as required, there must be at least 1 reference specified.
+Some documents allow multiple references, and they are documented as required.
+
+The document reference serves two purposes:
+
+1. It ensures that the document referenced by an ID/Version is not substituted.
+ In other words, that the document intended to be referenced, is actually referenced.
+2. It Allows the document to be unambiguously located in decentralized storage systems.
+
+There can be any number of Document Locations in any reference.
+The currently defined locations are:
+
+* `cid` : A [CBOR Encoded IPLD Content Identifier][CBOR-TAG-42] ( AKA an [IPFS CID][IPFS-CID] ).
+* Others may be added when further storage mechanisms are defined.
+
+The document location does not guarantee that the document is actually stored.
+It only defines that if it were stored, this is the identifier
+that is required to retrieve it.
+Therefore it is required that Document References
+are unique and reproducible, given a documents contents.
+
+#### [`ref`](../metadata.md#ref) Validation
+
+The following must be true for a valid reference:
+
+* The Referenced Document **MUST** Exist
+* Every value in the `document_locator` must consistently reference the exact same document.
+* The `document_id` and `document_ver` **MUST** match the values in the referenced document.
+
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Rep Nomination Form Template](rep_nomination_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Contest Parameters](contest_parameters.md) |
+| Linked Reference Metadata | [`template`](#template) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+* The Document referenced by [`template`](../metadata.md#template)
+ * MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
+ * MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
+
+## Payload
+
+The Representative's profile data for a specific contest.
+Its structure is defined by the referenced template document.
+
+In the case of Revoking a nomination the payload is `nil`.
+
+## Signers
+
+The following User roles may sign documents of this type:
+
+* Representative
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-06-19 |
+| Authors | Alex Pozhylenkov |
+| | Neil McAuliffe |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-06-19)
+
+* First Published Version
+
+[CBOR-TAG-42]: https://github.com/ipld/cid-cbor/
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[IPFS-CID]: https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination_form_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination_form_template.md
new file mode 100644
index 0000000000..4e739a9e96
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/rep_nomination_form_template.md
@@ -0,0 +1,184 @@
+# Rep Nomination Form Template
+
+## Description
+
+A Rep Nomination Form Template defines both:
+
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
+
+A Rep Nomination Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Rep Nomination entry *SHOULD* use the hints when collecting
+data defined by the Rep Nomination Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Rep Nomination Presentation Template can be used to
+format the Rep Nomination data for presentation.
+
+The Rep Nomination Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Rep Nomination.
+
+The payload of a Rep Nomination is controlled by its template.
+
+
+
+```graphviz dot rep_nomination_form_template.dot.svg
+{{ include_file('./../diagrams/rep_nomination_form_template.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+### Business Logic
+
+#### Front End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+#### Back End
+
+This specification outlines the required definitions for the current features.
+The document will be incrementally improved in future iterations as more functionality
+and features are added.
+This section will be included and updated in future iterations.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/schema+json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `bf9abd97-5d1f-4429-8e80-740fea371a9c`, `94579df1-a6dc-433b-a8e8-910c5dc2f0e3` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Contest Parameters](contest_parameters.md) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+## Payload
+
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Rep Nomination Document.
+
+## Signers
+
+The following Admin roles may sign documents of this type:
+
+* Brand Admin
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-05-30 |
+| Authors | Alex Pozhylenkov |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-04-04)
+
+* First Published Version
+
+#### 0.03 (2025-05-05)
+
+* Use generalized parameters.
+
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/rep_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/rep_profile.md
new file mode 100644
index 0000000000..d246251f89
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/rep_profile.md
@@ -0,0 +1,213 @@
+# Rep Profile
+
+## Description
+
+A Rep Profile allows a representative voter to publish information
+about themselves to help explain who they are and why someone should
+consider delegating to them.
+
+It is an extension of all other profiles attached to the same Catalyst ID.
+
+Profiles themselves are intentionally general, however they may be
+linked to a brand via the template used by the profile.
+
+The payload of a profile is controlled by its template.
+
+
+
+```graphviz dot rep_profile.dot.svg
+{{ include_file('./../diagrams/rep_profile.dot', indent=4) }}
+```
+
+
+
+### Validation
+
+* The signer MUST be a registered 'Representative'.
+* The payload MUST be valid against the [JSON schema][JSON Schema-2020-12] defined in the referenced
+'Rep Profile Template'.
+
+### Business Logic
+
+#### Front End
+
+* Display and allow editing of the Representative's core profile fields.
+* This profile serves as the central hub for a Representative's public identity.
+
+#### Back End
+
+* Validate Representative profile data against the referenced 'Rep Profile Template' and store/index it.
+* This global profile is the foundational document referenced by all of the Rep's contest specific profiles.
+
+## [COSE Header Parameters][RFC9052-HeaderParameters]
+
+* [content type](../spec.md#content-type) = `application/json`
+* [content-encoding](../spec.md#content-encoding) = `[br]`
+
+## Metadata
+
+### [`type`](../metadata.md#type)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Type](../metadata.md#document-type) |
+| Type | `0f2c86a2-ffda-40b0-ad38-23709e1c10b3`, `94579df1-a6dc-433b-a8e8-910c5dc2f0e3` |
+
+The document TYPE.
+
+#### [`type`](../metadata.md#type) Validation
+
+**MUST** be a known document type.
+
+### [`id`](../metadata.md#id)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Id](../metadata.md#document-id) |
+
+Document ID, created the first time the document is created.
+This must be a properly created [UUIDv7][RFC9562-V7] which contains the
+timestamp of when the document was created.
+
+#### [`id`](../metadata.md#id) Validation
+
+IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with
+[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist.
+
+### [`ver`](../metadata.md#ver)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Ver](../metadata.md#document-ver) |
+
+The unique version of the document.
+The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
+#### [`ver`](../metadata.md#ver) Validation
+
+The document version must always be >= the document ID.
+
+### [`template`](../metadata.md#template)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Rep Profile Form Template](rep_profile_form_template.md) |
+
+Reference to the template used to create and/or validate this document.
+
+#### [`template`](../metadata.md#template) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields,
+The document payload is not valid if it does not validate completely against the referenced template.
+
+### [`revocations`](../metadata.md#revocations)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Version Revocations](../metadata.md#version-revocations) |
+
+A document may include a list of any prior versions which are considered to be revoked.
+Only the revocation list in the latest version of the document applies.
+Revoked documents are flagged as no longer valid, and should not be displayed.
+As a special case, if the revocations are set to `true` then all versions of the document
+are revoked, including the latest document.
+
+In this case, when the latest document is revoked, the payload may be empty.
+Any older document that has [`revocations`](../metadata.md#revocations) set to `true` is always to be filtered
+and its payload is to be assumed to be invalid.
+
+This allows for an entire document and any/all published versions to be revoked.
+A new version of the document that is published after this, may reinstate prior
+document versions, by not listing them as revoked.
+However, any document where revocations was set `true` can never be reinstated.
+
+#### [`revocations`](../metadata.md#revocations) Validation
+
+If the field is `true` the payload may be absent or invalid.
+Such documents may never be submitted.
+
+### [`parameters`](../metadata.md#parameters)
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | yes |
+| Format | [Document Reference](../metadata.md#document-reference) |
+| Valid References | [Brand Parameters](brand_parameters.md) |
+| Linked Reference Metadata | [`template`](#template) |
+
+A reference to the Parameters Document this document lies under.
+
+#### [`parameters`](../metadata.md#parameters) Validation
+
+In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
+
+* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+* The Document referenced by [`template`](../metadata.md#template)
+ * MUST contain [`parameters`](../metadata.md#parameters) metadata; AND
+ * MUST match the referencing documents [`parameters`](../metadata.md#parameters) value.
+
+## Payload
+
+The Representative profile payload contains all Representative-specific fields.
+Its structure is defined by the referenced Rep Profile Template.
+
+Must be valid according to the schema contained within the
+[Document Reference](../metadata.md#document-reference) from the [`template`](../metadata.md#template) metadata.
+
+## Signers
+
+The following User roles may sign documents of this type:
+
+* Representative
+
+New versions of this document may be published by:
+
+* author
+
+## Copyright
+
+| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved |
+| --- | --- |
+| License | This document is licensed under [CC-BY-4.0] |
+| Created | 2024-12-27 |
+| Modified | 2025-06-19 |
+| Authors | Alex Pozhylenkov |
+| | Neil McAuliffe |
+| | Steven Johnson |
+
+### Changelog
+
+#### 0.01 (2025-06-19)
+
+* First Published Version
+
+[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
+[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
+[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/rep_profile_form_template.md
similarity index 66%
rename from docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md
rename to docs/src/architecture/08_concepts/signed_doc/docs/rep_profile_form_template.md
index 9ff14e8810..ce9de58497 100644
--- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md
+++ b/docs/src/architecture/08_concepts/signed_doc/docs/rep_profile_form_template.md
@@ -1,18 +1,32 @@
-# Proposal Meta Template
+# Rep Profile Form Template
## Description
-## Proposal Meta Template Document
+A Rep Profile Form Template defines both:
-A Proposal Meta Template is used to enforce functional requirements
-are met in any Proposal Template.
+* The data that is entered in the Form.
+* Formatting hints for the collection of the data in a form.
-The payload of a proposal template is controlled by its meta template.
+A Rep Profile Form Template is a [JSON Schema][JSON Schema-2020-12] Document.
+
+Rep Profile entry *SHOULD* use the hints when collecting
+data defined by the Rep Profile Form Template to provide a
+consistent user interface.
+It *CAN* also use those hints when re-displaying the full forms data.
+
+Alternatively a Rep Profile Presentation Template can be used to
+format the Rep Profile data for presentation.
+
+The Rep Profile Document is intentionally general,
+however it may be linked to a brand/campaign or category
+via the template used by the Rep Profile.
+
+The payload of a Rep Profile is controlled by its template.
-```graphviz dot proposal_meta_template.dot.svg
-{{ include_file('./../diagrams/proposal_meta_template.dot', indent=4) }}
+```graphviz dot rep_profile_form_template.dot.svg
+{{ include_file('./../diagrams/rep_profile_form_template.dot', indent=4) }}
```
@@ -54,7 +68,7 @@ This section will be included and updated in future iterations.
| --- | --- |
| Required | yes |
| Format | [Document Type](../metadata.md#document-type) |
-| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `7808d2ba-d511-40af-84e8-c0d1625fdfdc` |
+| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`, `0f2c86a2-ffda-40b0-ad38-23709e1c10b3`, `94579df1-a6dc-433b-a8e8-910c5dc2f0e3` |
The document TYPE.
@@ -90,6 +104,8 @@ IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a docu
The unique version of the document.
The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id)
+[`ver`](../metadata.md#ver) represents new versions of the same document as it changes over time.
+
#### [`ver`](../metadata.md#ver) Validation
The document version must always be >= the document ID.
@@ -102,8 +118,6 @@ The document version must always be >= the document ID.
| Required | yes |
| Format | [Document Reference](../metadata.md#document-reference) |
| Valid References | [Brand Parameters](brand_parameters.md) |
-| | [Campaign Parameters](campaign_parameters.md) |
-| | [Category Parameters](category_parameters.md) |
A reference to the Parameters Document this document lies under.
@@ -112,23 +126,28 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](../metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](../metadata.md#parameters) metadata must match the
-[`parameters`](../metadata.md#parameters) of the referencing document.
+[`parameters`](../metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](../metadata.md#parameters).
-## Payload
+For example, a linked reference to [Contest Parameters](contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
-[JSON Schema] document which ensures the minimum required functional requirements
-of the Proposal Template are met.
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
-This ensures that payloads can be reliably interpreted by business logic processes,
-while allowing for flexibility to capture extended information.
+## Payload
-Must be a valid according to .
+[JSON Schema][JSON Schema-2020-12] document which defines the valid contents and
+formatting hints for the collection of data for a
+Rep Profile Document.
## Signers
-The following admin roles may sign documents of this type:
+The following Admin roles may sign documents of this type:
-* Root Admin
* Brand Admin
New versions of this document may be published by:
@@ -141,7 +160,7 @@ New versions of this document may be published by:
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
@@ -155,7 +174,11 @@ New versions of this document may be published by:
* Use generalized parameters.
+#### 0.04 (2025-05-05)
+
+* Generalize the Form Template definitions.
+
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
-[JSON Schema]: https://json-schema.org/draft-07
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
diff --git a/docs/src/architecture/08_concepts/signed_doc/metadata.md b/docs/src/architecture/08_concepts/signed_doc/metadata.md
index 7b6fdc2e13..c534104c9f 100644
--- a/docs/src/architecture/08_concepts/signed_doc/metadata.md
+++ b/docs/src/architecture/08_concepts/signed_doc/metadata.md
@@ -5,6 +5,21 @@
The following types of metadata have been defined.
All Metadata fields use one of these types.
+### Chain Link
+
+A link to a previous document in a chained sequence.
+
+
+??? note "CDDL Specification"
+
+ * [cddl/chain.cddl](cddl/chain.cddl)
+
+ ```cddl
+ {{ include_file('./cddl/chain.cddl', indent=4) }}
+ ```
+
+
+
### Collaborators Reference List
A list of collaborators who can participate in drafting and submitting a document
@@ -42,10 +57,10 @@ A document reference identifier
??? note "CDDL Specification"
- * [cddl/document_ref.cddl](cddl/document_ref.cddl)
+ * [cddl/document_refs.cddl](cddl/document_refs.cddl)
```cddl
- {{ include_file('./cddl/document_ref.cddl', indent=4) }}
+ {{ include_file('./cddl/document_refs.cddl', indent=4) }}
```
@@ -184,6 +199,17 @@ IF [`ver`](metadata.md#ver) does not == [`id`](metadata.md#id) then a document w
The unique version of the document.
The first version of the document must set [`ver`](metadata.md#ver) == [`id`](metadata.md#id)
+[`ver`](metadata.md#ver) represents either:
+
+* when a document changes over time, such as
+ with a new version of a particular document that supersedes an
+ earlier one.
+* when a new document in a sequence of documents is produced.
+
+Because the most common use [`ver`](metadata.md#ver) is a new version of the same document
+this is to be assumed unless the document specifies its representing
+a sequence of documents.
+
#### `ver` Validation
The document version must always be >= the document ID.
@@ -195,19 +221,28 @@ The document version must always be >= the document ID.
| --- | --- |
| Required | optional |
| Format | [Document Reference](metadata.md#document-reference) |
-| Valid References | [Proposal Meta Template](./docs/proposal_meta_template.md) |
-| | [Proposal Template](./docs/proposal_template.md) |
+| Valid References | [Proposal Form Template](./docs/proposal_form_template.md) |
+| | [Proposal Presentation Template](./docs/proposal_presentation_template.md) |
| | [Proposal](./docs/proposal.md) |
-| | [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) |
-| | [Proposal Comment Template](./docs/proposal_comment_template.md) |
+| | [Proposal Comment Form Template](./docs/proposal_comment_form_template.md) |
+| | [Proposal Comment Presentation Template](./docs/proposal_comment_presentation_template.md) |
| | [Proposal Comment](./docs/proposal_comment.md) |
| | [Proposal Submission Action](./docs/proposal_submission_action.md) |
| | [Proposal Moderation Action](./docs/proposal_moderation_action.md) |
| | [Comment Moderation Action](./docs/comment_moderation_action.md) |
| | [Brand Parameters](./docs/brand_parameters.md) |
+| | [Brand Parameters Form Template](./docs/brand_parameters_form_template.md) |
| | [Campaign Parameters](./docs/campaign_parameters.md) |
+| | [Campaign Parameters Form Template](./docs/campaign_parameters_form_template.md) |
| | [Category Parameters](./docs/category_parameters.md) |
-| | [Decision Parameters](./docs/decision_parameters.md) |
+| | [Category Parameters Form Template](./docs/category_parameters_form_template.md) |
+| | [Contest Parameters](./docs/contest_parameters.md) |
+| | [Contest Parameters Form Template](./docs/contest_parameters_form_template.md) |
+| | [Rep Profile](./docs/rep_profile.md) |
+| | [Rep Profile Form Template](./docs/rep_profile_form_template.md) |
+| | [Rep Nomination](./docs/rep_nomination.md) |
+| | [Rep Nomination Form Template](./docs/rep_nomination_form_template.md) |
+| | [Contest Delegation](./docs/contest_delegation.md) |
Reference to a Linked Document or Documents.
This is the primary hierarchical reference to a related document.
@@ -248,10 +283,14 @@ The following must be true for a valid reference:
| --- | --- |
| Required | optional |
| Format | [Document Reference](metadata.md#document-reference) |
-| Valid References | [Proposal Meta Template](./docs/proposal_meta_template.md) |
-| | [Proposal Template](./docs/proposal_template.md) |
-| | [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) |
-| | [Proposal Comment Template](./docs/proposal_comment_template.md) |
+| Valid References | [Proposal Form Template](./docs/proposal_form_template.md) |
+| | [Proposal Comment Form Template](./docs/proposal_comment_form_template.md) |
+| | [Brand Parameters Form Template](./docs/brand_parameters_form_template.md) |
+| | [Campaign Parameters Form Template](./docs/campaign_parameters_form_template.md) |
+| | [Category Parameters Form Template](./docs/category_parameters_form_template.md) |
+| | [Contest Parameters Form Template](./docs/contest_parameters_form_template.md) |
+| | [Rep Profile Form Template](./docs/rep_profile_form_template.md) |
+| | [Rep Nomination Form Template](./docs/rep_nomination_form_template.md) |
Reference to the template used to create and/or validate this document.
@@ -331,7 +370,7 @@ addition to the author.
| Valid References | [Brand Parameters](./docs/brand_parameters.md) |
| | [Campaign Parameters](./docs/campaign_parameters.md) |
| | [Category Parameters](./docs/category_parameters.md) |
-| | [Decision Parameters](./docs/decision_parameters.md) |
+| | [Contest Parameters](./docs/contest_parameters.md) |
A reference to the Parameters Document this document lies under.
@@ -340,7 +379,249 @@ A reference to the Parameters Document this document lies under.
In addition to the validation performed for [Document Reference](metadata.md#document-reference) type fields:
* Any linked referenced document that includes a [`parameters`](metadata.md#parameters) metadata must match the
-[`parameters`](metadata.md#parameters) of the referencing document.
+[`parameters`](metadata.md#parameters) of the referencing document,
+or a parent of those [`parameters`](metadata.md#parameters).
+
+For example, a linked reference to [Contest Parameters](./docs/contest_parameters.md) is transitively a reference to
+the Parameters document it references, and each parameters document they reference
+until the `Brand` parameters document is reached.
+
+The use case here is for Templates.
+The profile template, or proposal templates could be defined at any of these
+levels, and as long as they all refer to the same chain of parameters in the
+hierarchy they are all valid.
+
+### `chain`
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | optional |
+| Format | [Chain Link](metadata.md#chain-link) |
+
+An immutable link to the previous document in a chained sequence of documents.
+Because ID/Ver only defines values for the current document, and is not intended
+by itself to prevent insertion of documents in a sequence, the [`chain`](metadata.md#chain)
+metadata allows for the latest document to directly point to its previous iteration.
+
+It also aids in discoverability, where the latest document may be pinned but prior
+documents can be discovered automatically by following the chain.
+
+#### `chain` Validation
+
+Chained Documents do not support collaborators.
+Any document which is attempted to be published in the sequence
+which is *NOT* published by the author of the first document in the
+sequence is fraudulent, and to be discarded.
+
+In addition, the chained document *MUST*:
+
+* Not have `collaborators`;
+* Have the same [`id`](metadata.md#id) as the document being chained to;
+* Have a [`ver`](metadata.md#ver) that is greater than the [`ver`](metadata.md#ver) being chained to;
+* Have the same [`type`](metadata.md#type) as the chained document;
+* Have [`parameters`](metadata.md#parameters) match;
+* Have not be chaining to a document already chained to by another document;
+* Have its absolute `height` exactly one more than the `height` of the document being chained to.
+
+IF any of these validations fail, then the entire sequence of documents is INVALID.
+Not just the current document.
+
+##### Example of a Valid Chain
+
+
+``` mermaid
+classDiagram
+ direction LR
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#060,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#060,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#060,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
+
+```
+
+
+##### Example of an Invalid Chain
+
+Either of the two documents being present invalidates the data
+in the entire chain,
+as they are signed by the author of the chain.
+
+
+``` mermaid
+classDiagram
+ direction LR
+
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#f60,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#f60,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#f60,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
+ class Invalid_Chain {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+
+ Invalid_Chain --|> First : Invalidly chains to
+ style Invalid_Chain fill:#100,stroke:#f00,stroke-width:4px
+
+
+ class After_Final {
+ type: "=Final.Document Type"
+ id: "=Final.Document ID"
+ ver: ">Final.Document ID"
+ parameters: "=Final.Document Parameters"
+ chain.height: 3
+ chain.document_ref: "=Last"
+
+ author(Last.Catalyst ID)
+ }
+
+ After_Final --|> Last : Invalidly chains to
+ style After_Final fill:#100,stroke:#f00,stroke-width:4px
+
+```
+
+
+##### Example of a Fraudulent Chain Document
+
+The invalid document does not invalidate the chain,
+as its not signed by the author of the chained documents.
+
+
+``` mermaid
+classDiagram
+ direction LR
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#060,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#060,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#060,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
+ class Rejected {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(Other.Catalyst ID)
+ }
+
+ Rejected --|> Intermediate : Invalidly chains to
+ style Rejected fill:#100,stroke:#f00,stroke-width:4px
+
+```
+
## Copyright
@@ -348,7 +629,7 @@ In addition to the validation performed for [Document Reference](metadata.md#doc
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/docs/src/architecture/08_concepts/signed_doc/schema/template_example.schema.json b/docs/src/architecture/08_concepts/signed_doc/schema/template_example.schema.json
new file mode 100644
index 0000000000..29bd6010ed
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/schema/template_example.schema.json
@@ -0,0 +1,254 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema#",
+ "title": "Example Template Schema",
+ "description": "Example Template Schema showing all defined field types.",
+ "maintainers": [
+ {
+ "name": "Catalyst Team",
+ "url": "https://projectcatalyst.io/"
+ }
+ ],
+ "$defs": {
+ "dropDownSingleSelect": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "multiLineTextEntry": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "multiLineTextEntryListMarkdown": {
+ "items": {
+ "contentMediaType": "text/markdown",
+ "minLength": 1,
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "multiLineTextEntryMarkdown": {
+ "contentMediaType": "text/markdown",
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "multiSelect": {
+ "items": {
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "radioButtonSelect": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "schemaReferenceNonUI": {
+ "readOnly": true,
+ "type": "string"
+ },
+ "section": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "segment": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "singleGroupedTagSelector": {
+ "additionalProperties": false,
+ "required": [
+ "group",
+ "tag"
+ ],
+ "type": "object"
+ },
+ "singleLineHttpsURLEntry": {
+ "format": "uri",
+ "pattern": "^https://[^\\s]+$",
+ "type": "string"
+ },
+ "singleLineHttpsURLEntryList": {
+ "items": {
+ "format": "uri",
+ "minLength": 1,
+ "pattern": "^https://[^\\s]+$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "singleLineTextEntry": {
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "singleLineTextEntryList": {
+ "items": {
+ "minLength": 1,
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "dropDownSingleSelect": {
+ "exampleDropDownSingleSelect": {
+ "description": null,
+ "enum": null,
+ "title": null,
+ "x-guidance": null
+ },
+ "$ref": "#/$defs/dropDownSingleSelect"
+ },
+ "multiLineTextEntry": {
+ "exampleMultiLineTextEntry": {
+ "description": null,
+ "maxLength": null,
+ "minLength": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/multiLineTextEntry"
+ },
+ "multiLineTextEntryListMarkdown": {
+ "exampleMultiLineTextEntryListMarkdown": {
+ "contains": null,
+ "default": null,
+ "description": null,
+ "maxItems": null,
+ "minItems": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/multiLineTextEntryListMarkdown"
+ },
+ "multiLineTextEntryMarkdown": {
+ "exampleMultiLineTextEntryMarkdown": {
+ "description": null,
+ "maxLength": null,
+ "minLength": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/multiLineTextEntryMarkdown"
+ },
+ "multiSelect": {
+ "exampleMultiSelect": {
+ "contains": null,
+ "default": null,
+ "description": null,
+ "maxItems": null,
+ "minItems": null,
+ "title": null,
+ "x-guidance": null
+ },
+ "$ref": "#/$defs/multiSelect"
+ },
+ "radioButtonSelect": {
+ "exampleRadioButtonSelect": {
+ "description": null,
+ "enum": null,
+ "title": null,
+ "x-guidance": null
+ },
+ "$ref": "#/$defs/radioButtonSelect"
+ },
+ "schemaReferenceNonUI": {
+ "exampleSchemaReferenceNonUI": {
+ "const": null,
+ "default": null
+ },
+ "$ref": "#/$defs/schemaReferenceNonUI"
+ },
+ "section": {
+ "exampleSection": {
+ "description": null,
+ "properties": null,
+ "required": null,
+ "title": null,
+ "x-icon": null,
+ "x-order": null
+ },
+ "$ref": "#/$defs/section"
+ },
+ "segment": {
+ "exampleSegment": {
+ "description": null,
+ "properties": null,
+ "required": null,
+ "title": null,
+ "x-icon": null,
+ "x-order": null
+ },
+ "$ref": "#/$defs/segment"
+ },
+ "singleGroupedTagSelector": {
+ "exampleSingleGroupedTagSelector": {
+ "description": null,
+ "oneOf_groupedTags": null,
+ "title": null,
+ "x-guidance": null
+ },
+ "$ref": "#/$defs/singleGroupedTagSelector"
+ },
+ "singleLineHttpsURLEntry": {
+ "exampleSingleLineHttpsURLEntry": {
+ "description": null,
+ "maxLength": null,
+ "minLength": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/singleLineHttpsURLEntry"
+ },
+ "singleLineHttpsURLEntryList": {
+ "exampleSingleLineHttpsURLEntryList": {
+ "contains": null,
+ "default": null,
+ "description": null,
+ "maxItems": null,
+ "minItems": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/singleLineHttpsURLEntryList"
+ },
+ "singleLineTextEntry": {
+ "exampleSingleLineTextEntry": {
+ "description": null,
+ "maxLength": null,
+ "minLength": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/singleLineTextEntry"
+ },
+ "singleLineTextEntryList": {
+ "exampleSingleLineTextEntryList": {
+ "contains": null,
+ "default": null,
+ "description": null,
+ "maxItems": null,
+ "minItems": null,
+ "title": null,
+ "x-guidance": null,
+ "x-placeholder": null
+ },
+ "$ref": "#/$defs/singleLineTextEntryList"
+ }
+ }
+}
diff --git a/docs/src/architecture/08_concepts/signed_doc/spec.md b/docs/src/architecture/08_concepts/signed_doc/spec.md
index f2cc3a81bb..b61bcb00a2 100644
--- a/docs/src/architecture/08_concepts/signed_doc/spec.md
+++ b/docs/src/architecture/08_concepts/signed_doc/spec.md
@@ -25,6 +25,40 @@ Catalyst Signed Documents are based on [COSE][RFC9052].
Specifically, the [COSE Sign][RFC9052-CoseSign] format is used.
This allows one or more signatures to be attached to the same document.
+While every Catalyst Signed Document is a valid [COSE Sign][RFC9052-CoseSign] format document,
+not every [COSE Sign][RFC9052-CoseSign] format document is a valid Catalyst Signed Document.
+The following restrictions apply:
+
+### Unprotected Headers are not permitted
+
+It is a requirement that any document that contains exactly the same data, must produce the same
+catalyst signed document.
+This means that unprotected headers, which do not form part of the data protected by
+the signature are not permitted.
+Any document which contains any unprotected headers is not a valid Catalyst Signed Document,
+even though it may be a valid [COSE Sign][RFC9052-CoseSign] formatted document.
+
+### Only defined metadata and [COSE][RFC9052] Headers are allowed
+
+Each document type, defines a set of metadata and the [COSE][RFC9052] Headers which are allowed in that document type.
+Even if the Catalyst Signed document metadata exists in this specification, IF it is not defined as
+a valid metadata or [COSE][RFC9052] Header field for that particular document it may not be present.
+Unexpected but otherwise valid Metadata or [COSE][RFC9052] Header fields invalidate the Catalyst Signed Document.
+
+### No undefined metadata or unused [COSE][RFC9052] Headers may be present
+
+[COSE][RFC9052] Header Fields which are defined by the [COSE][RFC9052] Specification, but are NOT defined as part of a
+Catalyst Signed Document may not be present.
+Any such [COSE][RFC9052] Header Fields present in the document render it an invalid Catalyst Signed Document.
+
+Any metadata field that is not defined in this specification may not be present in any protected header.
+Unrecognized metadata fields in a document render it an invalid Catalyst Signed Document.
+
+### [CBOR Deterministic Encoding][CBOR-LFD-ENCODING] MUST be used
+
+The Catalyst Signed Document **MUST** be encoded using [CBOR Deterministic Encoding][CBOR-LFD-ENCODING].
+The "length-first core deterministic encoding requirements" variant of deterministic encoding *MUST* be used.
+
### Signed Document [CDDL][RFC8610] Definition
@@ -64,15 +98,78 @@ Media Type/s allowed in the Payload
* [Cose][RFC9052] Label : 3
* Format : Media Type
* Supported Values:
- * [application/json] : [JSON][RFC8259] Document
- * [application/schema+json] : [JSON Schema] Draft 7 Document; Note:
- * This is currently an unofficial media type.
- * Draft 7 is used because of its wide support by tooling.
- * [application/cbor] : [RFC8949] Binary [CBOR][RFC8949] Encoded Document
- * application/cddl : [CDDL][RFC8610] Document; Note:
+ * [application/cbor] :
+ An [RFC8949] Binary [CBOR][RFC8949] Encoded Document.
+ * [application/cddl][RFC8610] :
+ A [CDDL][RFC8610] Document.
+
+ Note:
+
* This is an unofficial media type
* [RFC9165] Additional Control Operators for [CDDL][RFC8610] are supported.
* Must not have Modules, schema must be self-contained.
+ * [application/json] :
+ [JSON][RFC8259] Document
+ * [application/schema+json][JSON Schema-2020-12] :
+ A [JSON Schema Draft 2020-12][JSON Schema-2020-12] Document.
+
+ Note:
+
+ * This is currently an unofficial media type.
+ * [text/css;][text/css] [charset=utf-8][RFC3629] :
+ [CSS] Content used for styling [HTML][HTML5].
+ [CSS] should use the least set of features possible to achieve
+ the desired presentation to ensure the broadest compatibility.
+ * [text/css;][text/css] [charset=utf-8;][RFC3629] [template=handlebars][Handlebars] :
+ [CSS] Content used for styling [HTML][HTML5].
+ [CSS] should use the least set of features possible to achieve
+ the desired presentation to ensure the broadest compatibility.
+
+ The text includes [Handlebars] type template fields that need
+ processing and replacement prior to display.
+ * [text/html;][HTML5] [charset=utf-8][RFC3629] :
+ Formatted text using [HTML5] markup for rich text.
+ Only [HTML5] syntax is supported.
+ * [text/html;][HTML5] [charset=utf-8;][RFC3629] [template=handlebars][Handlebars] :
+ Formatted text using [HTML5] markup for rich text.
+ Only [HTML5] syntax is supported.
+
+ The text includes [Handlebars] type template fields that need
+ processing and replacement prior to display.
+ * [text/markdown;][CommonMark] [charset=utf-8][RFC3629] :
+ Formatted text using [Markdown][CommonMark] for rich text.
+ [Markdown][CommonMark] formatting is as defined by [CommonMark].
+
+ IF the document includes HTML, then [HTML5] syntax only is supported.
+
+ The following [Markdown][CommonMark] Extensions are also supported:
+
+ * None
+ * [text/markdown;][CommonMark] [charset=utf-8;][RFC3629] [template=handlebars][Handlebars] :
+ Formatted text using [Markdown][CommonMark] for rich text.
+ [Markdown][CommonMark] formatting is as defined by [CommonMark].
+
+ IF the document includes HTML, then [HTML5] syntax only is supported.
+
+ The following [Markdown][CommonMark] Extensions are also supported:
+
+ * None
+
+ The text includes [Handlebars] type template fields that need
+ processing and replacement prior to display.
+ * [text/plain;][text/plain] [charset=utf-8][RFC3629] :
+ Plain Text with no markup or special formatting.
+ Multiline Plain Text *MUST* always interpret `
+ `
+ as a hard line break.
+ * [text/plain;][text/plain] [charset=utf-8;][RFC3629] [template=handlebars][Handlebars] :
+ Plain Text with no markup or special formatting.
+ Multiline Plain Text *MUST* always interpret `
+ `
+ as a hard line break.
+
+ The text includes [Handlebars] type template fields that need
+ processing and replacement prior to display.
#### `content-encoding`
@@ -83,12 +180,12 @@ If no compression or encoding is used, then this field must not be present.
* [Cose][RFC9052] Label : content-encoding ***Custom Header***
* Format : HTTP Content Encoding
* Supported Values:
- * [br] : [BROTLI][RFC7932] Compression
+ * [br] :
+ [BROTLI][RFC7932] Compression
### Metadata
-Catalyst Signed Documents extend the Header Parameters with a series of Metadata fields.
-These fields are defined [here](./metadata.md).
+Catalyst Signed Documents extend the Header Parameters with a series of [Metadata fields](./metadata.md).
### Signing Catalyst Signed Documents
@@ -120,7 +217,7 @@ used to sign the protected portion of the document.
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
@@ -138,19 +235,33 @@ used to sign the protected portion of the document.
* Use generalized parameters.
-[application/schema+json]: https://datatracker.ietf.org/doc/draft-bhutton-json-schema/
+#### 0.04 (2025-05-30)
+
+* Improve and make document serialization more repeatable, and stricter.
+* TODO: Define Systems parameters
+* TODO: Define DReps documents.
+* TODO: Define Proposer Profiles.
+* TODO: Define Role 0 Profile.
+
+[CBOR-LFD-ENCODING]: https://www.rfc-editor.org/rfc/rfc8949.html#section-4.2.3
+[JSON Schema-2020-12]: https://json-schema.org/draft/2020-12
[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1
+[Handlebars]: https://handlebarsjs.com/
+[RFC8610]: https://www.rfc-editor.org/rfc/rfc8610
[application/cbor]: https://www.iana.org/assignments/media-types/application/cbor
[application/json]: https://www.iana.org/assignments/media-types/application/json
-[JSON Schema]: https://json-schema.org/draft-07
+[RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
+[CommonMark]: https://spec.commonmark.org/0.31.2/
+[text/plain]: https://www.rfc-editor.org/rfc/rfc2046.html
+[HTML5]: https://html.spec.whatwg.org/multipage/syntax.html#syntax
[RFC9052-CoseSign]: https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si
+[text/css]: https://www.rfc-editor.org/rfc/rfc2318.html
[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode
[RFC8949]: https://www.rfc-editor.org/rfc/rfc8949.html
[RFC9165]: https://www.rfc-editor.org/rfc/rfc9165
[RFC7932]: https://www.rfc-editor.org/rfc/rfc7932
-[RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629
-[RFC8610]: https://www.rfc-editor.org/rfc/rfc8610
[RFC9052]: https://datatracker.ietf.org/doc/html/rfc9052
[RFC8259]: https://www.rfc-editor.org/rfc/rfc8259.html
[RFC3986]: https://datatracker.ietf.org/doc/html/rfc3986
+[CSS]: https://www.w3.org/Style/CSS/
[br]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br
diff --git a/docs/src/architecture/08_concepts/signed_doc/templates.md b/docs/src/architecture/08_concepts/signed_doc/templates.md
new file mode 100644
index 0000000000..56934c598f
--- /dev/null
+++ b/docs/src/architecture/08_concepts/signed_doc/templates.md
@@ -0,0 +1 @@
+# Templates"
diff --git a/docs/src/architecture/08_concepts/signed_doc/types.md b/docs/src/architecture/08_concepts/signed_doc/types.md
index c9b878b78e..2a2ff9b9ae 100644
--- a/docs/src/architecture/08_concepts/signed_doc/types.md
+++ b/docs/src/architecture/08_concepts/signed_doc/types.md
@@ -11,11 +11,19 @@ All Document Types are defined by composing these base document types:
| Campaign | `5ef32d5d-f240-462c-a7a4-ba4af221fa23` | `37(h'5ef32d5df240462ca7a4ba4af221fa23')` |
| Category | `818938c3-3139-4daa-afe6-974c78488e95` | `37(h'818938c331394daaafe6974c78488e95')` |
| Comment | `b679ded3-0e7c-41ba-89f8-da62a17898ea` | `37(h'b679ded30e7c41ba89f8da62a17898ea')` |
-| Decision | `788ff4c6-d65a-451f-bb33-575fe056b411` | `37(h'788ff4c6d65a451fbb33575fe056b411')` |
+| Contest | `788ff4c6-d65a-451f-bb33-575fe056b411` | `37(h'788ff4c6d65a451fbb33575fe056b411')` |
+| Delegation | `764f17fb-cc50-4979-b14a-b213dbac5994` | `37(h'764f17fbcc504979b14ab213dbac5994')` |
+| FormTemplate | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f` | `37(h'0ce8ab3892584fbca62e7faa6e58318f')` |
| ModerationAction | `a5d232b8-5e03-4117-9afd-be32b878fcdd` | `37(h'a5d232b85e0341179afdbe32b878fcdd')` |
+| Nomination | `bf9abd97-5d1f-4429-8e80-740fea371a9c` | `37(h'bf9abd975d1f44298e80740fea371a9c')` |
+| Parameters | `60185874-7e13-407c-a06c-238ffe637ae6` | `37(h'601858747e13407ca06c238ffe637ae6')` |
+| PresentationTemplate | `cb99b9bd-681a-49d8-9836-89107c02e8ef` | `37(h'cb99b9bd681a49d8983689107c02e8ef')` |
+| Profile | `0f2c86a2-ffda-40b0-ad38-23709e1c10b3` | `37(h'0f2c86a2ffda40b0ad3823709e1c10b3')` |
| Proposal | `7808d2ba-d511-40af-84e8-c0d1625fdfdc` | `37(h'7808d2bad51140af84e8c0d1625fdfdc')` |
+| RegisteredProposer | `7311c63b-95c6-402e-a258-f9bf622093eb` | `37(h'7311c63b95c6402ea258f9bf622093eb')` |
+| RegisteredRep | `94579df1-a6dc-433b-a8e8-910c5dc2f0e3` | `37(h'94579df1a6dc433ba8e8910c5dc2f0e3')` |
+| RegisteredUser | `ff4b7724-3db5-44cd-a433-78ba6d29505e` | `37(h'ff4b77243db544cda43378ba6d29505e')` |
| SubmissionAction | `78927329-cfd9-4ea1-9c71-0e019b126a65` | `37(h'78927329cfd94ea19c710e019b126a65')` |
-| Template | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f` | `37(h'0ce8ab3892584fbca62e7faa6e58318f')` |
## Document Types
@@ -24,19 +32,28 @@ All Defined Document Types
| Document Type | Base Types | [CBOR][RFC8949] |
| :--- | :--- | :--- |
-| [Brand Parameters](./docs/brand_parameters.md) | Brand | [37(h'ebcabeeb5bc54f9591e8cab8ca724172')] |
-| [Campaign Parameters](./docs/campaign_parameters.md) | Campaign | [37(h'5ef32d5df240462ca7a4ba4af221fa23')] |
-| [Category Parameters](./docs/category_parameters.md) | Category | [37(h'818938c331394daaafe6974c78488e95')] |
+| [Brand Parameters](./docs/brand_parameters.md) | Parameters/Brand | [37(h'601858747e13407ca06c238ffe637ae6'), 37(h'ebcabeeb5bc54f9591e8cab8ca724172')] |
+| [Brand Parameters Form Template](./docs/brand_parameters_form_template.md) | FormTemplate/Parameters/Brand | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'601858747e13407ca06c238ffe637ae6'), 37(h'ebcabeeb5bc54f9591e8cab8ca724172')] |
+| [Campaign Parameters](./docs/campaign_parameters.md) | Parameters/Campaign | [37(h'601858747e13407ca06c238ffe637ae6'), 37(h'5ef32d5df240462ca7a4ba4af221fa23')] |
+| [Campaign Parameters Form Template](./docs/campaign_parameters_form_template.md) | FormTemplate/Parameters/Campaign | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'601858747e13407ca06c238ffe637ae6'), 37(h'5ef32d5df240462ca7a4ba4af221fa23')] |
+| [Category Parameters](./docs/category_parameters.md) | Parameters/Category | [37(h'601858747e13407ca06c238ffe637ae6'), 37(h'818938c331394daaafe6974c78488e95')] |
+| [Category Parameters Form Template](./docs/category_parameters_form_template.md) | FormTemplate/Parameters/Category | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'601858747e13407ca06c238ffe637ae6'), 37(h'818938c331394daaafe6974c78488e95')] |
| [Comment Moderation Action](./docs/comment_moderation_action.md) | Action/Comment/ModerationAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'), 37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'a5d232b85e0341179afdbe32b878fcdd')] |
-| [Decision Parameters](./docs/decision_parameters.md) | Decision | [37(h'788ff4c6d65a451fbb33575fe056b411')] |
+| [Contest Delegation](./docs/contest_delegation.md) | Delegation/Contest | [37(h'764f17fbcc504979b14ab213dbac5994'), 37(h'788ff4c6d65a451fbb33575fe056b411')] |
+| [Contest Parameters](./docs/contest_parameters.md) | Parameters/Contest | [37(h'601858747e13407ca06c238ffe637ae6'), 37(h'788ff4c6d65a451fbb33575fe056b411')] |
+| [Contest Parameters Form Template](./docs/contest_parameters_form_template.md) | FormTemplate/Parameters/Contest | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'601858747e13407ca06c238ffe637ae6'), 37(h'788ff4c6d65a451fbb33575fe056b411')] |
| [Proposal](./docs/proposal.md) | Proposal | [37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
| [Proposal Comment](./docs/proposal_comment.md) | Comment/Proposal | [37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
-| [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) | Template/Template/Comment/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
-| [Proposal Comment Template](./docs/proposal_comment_template.md) | Template/Comment/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
-| [Proposal Meta Template](./docs/proposal_meta_template.md) | Template/Template/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
+| [Proposal Comment Form Template](./docs/proposal_comment_form_template.md) | FormTemplate/Comment/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
+| [Proposal Comment Presentation Template](./docs/proposal_comment_presentation_template.md) | PresentationTemplate/Comment/Proposal | [37(h'cb99b9bd681a49d8983689107c02e8ef'), 37(h'b679ded30e7c41ba89f8da62a17898ea'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
+| [Proposal Form Template](./docs/proposal_form_template.md) | FormTemplate/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
| [Proposal Moderation Action](./docs/proposal_moderation_action.md) | Action/Proposal/ModerationAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'), 37(h'7808d2bad51140af84e8c0d1625fdfdc'), 37(h'a5d232b85e0341179afdbe32b878fcdd')] |
+| [Proposal Presentation Template](./docs/proposal_presentation_template.md) | PresentationTemplate/Proposal | [37(h'cb99b9bd681a49d8983689107c02e8ef'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
| [Proposal Submission Action](./docs/proposal_submission_action.md) | Action/Proposal/SubmissionAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'), 37(h'7808d2bad51140af84e8c0d1625fdfdc'), 37(h'78927329cfd94ea19c710e019b126a65')] |
-| [Proposal Template](./docs/proposal_template.md) | Template/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'7808d2bad51140af84e8c0d1625fdfdc')] |
+| [Rep Nomination](./docs/rep_nomination.md) | Nomination/RegisteredRep | [37(h'bf9abd975d1f44298e80740fea371a9c'), 37(h'94579df1a6dc433ba8e8910c5dc2f0e3')] |
+| [Rep Nomination Form Template](./docs/rep_nomination_form_template.md) | FormTemplate/Nomination/RegisteredRep | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'bf9abd975d1f44298e80740fea371a9c'), 37(h'94579df1a6dc433ba8e8910c5dc2f0e3')] |
+| [Rep Profile](./docs/rep_profile.md) | Profile/RegisteredRep | [37(h'0f2c86a2ffda40b0ad3823709e1c10b3'), 37(h'94579df1a6dc433ba8e8910c5dc2f0e3')] |
+| [Rep Profile Form Template](./docs/rep_profile_form_template.md) | FormTemplate/Profile/RegisteredRep | [37(h'0ce8ab3892584fbca62e7faa6e58318f'), 37(h'0f2c86a2ffda40b0ad3823709e1c10b3'), 37(h'94579df1a6dc433ba8e8910c5dc2f0e3')] |
## Document Relationship Hierarchy
@@ -55,7 +72,7 @@ All Defined Document Types
| --- | --- |
| License | This document is licensed under [CC-BY-4.0] |
| Created | 2024-12-27 |
-| Modified | 2025-05-05 |
+| Modified | 2025-05-30 |
| Authors | Alex Pozhylenkov |
| | Steven Johnson |
diff --git a/rust/signed_doc/src/validator/mod.rs b/rust/signed_doc/src/validator/mod.rs
index 0c755bdcb5..4bed4304a8 100644
--- a/rust/signed_doc/src/validator/mod.rs
+++ b/rust/signed_doc/src/validator/mod.rs
@@ -104,7 +104,7 @@ fn document_rules_init() -> HashMap {
.with_draft(jsonschema::Draft::Draft7)
.build(
&serde_json::from_str(include_str!(
- "./../../../../specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json"
+ "./../../../../specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json"
))
.expect("Must be a valid json file"),
)
diff --git a/specs/Earthfile b/specs/Earthfile
index bccf4b46d2..ddcad7701d 100644
--- a/specs/Earthfile
+++ b/specs/Earthfile
@@ -8,7 +8,7 @@ IMPORT ../docs AS docs
# Get cue binary
cue-bin:
- FROM cuelang/cue:0.12.0
+ FROM cuelang/cue:0.13.1
SAVE ARTIFACT /usr/bin/cue
@@ -30,18 +30,20 @@ src:
# Check that the generated signed docs data matches the src.
check:
FROM +src
- RUN cue fmt --check --files .
- RUN cue vet ./signed_docs/docs:signed_docs signed_doc.json
+ RUN cue fmt --check -s --files ./definitions
+ RUN cd definitions; CUE_EXPERIMENT=evalv3=0 cue vet ./signed_docs/docs:signed_docs ../signed_doc.json
# Check the the generated signed docs documentation matches the generated signed docs data
check-docs-generation:
FROM python-ci+python-base
- COPY ./gen_docs gen_docs
+ COPY ./generators generators
COPY +src/signed_doc.json .
COPY --dir docs+generated-signed-docs-pages/signed_doc signed_doc
# Check our validation code actually works properly
- RUN cd gen_docs; \
- ./main.py -o "../signed_doc" ../signed_doc.json
+ RUN cd generators; \
+ uv run validator ../signed_doc.json
+ RUN cd generators; \
+ uv run docs -o "../signed_doc" ../signed_doc.json
# Regenerate - using the builder
diff --git a/specs/Justfile b/specs/Justfile
index 1733cf995d..f759d2f313 100644
--- a/specs/Justfile
+++ b/specs/Justfile
@@ -10,34 +10,40 @@ default:
# Fix cue files. This also sets all the file times on the cue files to NOW.
# So it should only be run when required.
fix:
- cue fix ./signed_docs/docs:signed_docs
+ cue fix ./definitions/signed_docs/docs:signed_docs
+ cue fix ./definitions/form_template/fields:form_template
# Fix the format of cue files
format:
- cue fmt --files .
+ cue fmt -s --files ./definitions
# Check the signed document cue files are valid.
check: format
- cue vet ./signed_docs/docs:signed_docs -c
+ cd definitions; cue vet ./signed_docs/docs:signed_docs -c
+ cd definitions; cue vet ./form_template/fields:form_template -c
# Regenerate the full signed document specification json file.
regenerate-signed-doc-json:
# Make sure keys are sorted so its both reproducible, AND diffs easily.
- cue export -f -s ./signed_docs/docs:signed_docs --out json | jq -S > signed_doc.json
+ cd definitions; cue export -f -s ./signed_docs/docs:signed_docs --out json | jq -S > ../signed_doc.json
# Fix and Check Markdown files
regenerate: check regenerate-signed-doc-json validate && validate-docs
# Generate the markdown docs from the specification.
- cd gen_docs; ./main.py -g -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json
+ cd generators; uv run docs -g -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json
# Validate the generated signed_docs.json is correct against the cue schema.
validate:
- cue vet ./signed_docs/docs:signed_docs signed_doc.json
+ # Generate the intermediate compiled schema data.
+ cd definitions; CUE_EXPERIMENT=evalv3=0 cue vet ./signed_docs/docs:signed_docs ../signed_doc.json
+ # cd definitions; cue vet ./signed_docs/docs:signed_docs ../signed_doc.json
+ # Check the Model is valid.
+ cd generators; uv run validator ../signed_doc.json
# Validate the generated docs is correct against the signed_docs.json.
validate-docs:
# Check our validation code actually works properly
- cd gen_docs; ./main.py -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json
+ cd generators; uv run docs -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json
# Pre Push Checks - intended to be run by a git pre-push hook.
pre-push: format-python-code lint-python regenerate validate
diff --git a/specs/cue.mod/module.cue b/specs/cue.mod/module.cue
deleted file mode 100644
index aad96b47e7..0000000000
--- a/specs/cue.mod/module.cue
+++ /dev/null
@@ -1,4 +0,0 @@
-module: "github.com/input-output-hk/catalyst-libs/specs"
-language: {
- version: "v0.11.2"
-}
diff --git a/specs/definitions/cue.mod/module.cue b/specs/definitions/cue.mod/module.cue
new file mode 100644
index 0000000000..c882948267
--- /dev/null
+++ b/specs/definitions/cue.mod/module.cue
@@ -0,0 +1,4 @@
+module: "github.com/input-output-hk/catalyst-libs/specs@v0"
+language: {
+ version: "v0.13.0"
+}
diff --git a/specs/definitions/documentation/link_aka.cue b/specs/definitions/documentation/link_aka.cue
new file mode 100644
index 0000000000..cb6d59f82b
--- /dev/null
+++ b/specs/definitions/documentation/link_aka.cue
@@ -0,0 +1,61 @@
+package documentation
+
+import (
+ "list"
+)
+
+#linkAKAName: string
+
+linkAKA: [#linkAKAName]: #allLinkNames
+
+// Known aliases for links. Lets us automatically create [Named Link][Reference Link]
+linkAKA: {
+ UUIDv7: "RFC9562-V7"
+ UUIDv4: "RFC9562-V4"
+ UUID: "RFC9562"
+ URI: "RFC3986"
+ "UTF-8": "RFC3629"
+ "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42"
+ "IPFS CID": "IPFS-CID"
+ "CBOR Deterministic Encoding": "CBOR-LFD-ENCODING"
+ BROTLI: "RFC7932"
+ JSON: "RFC8259"
+ CDDL: "RFC8610"
+ CBOR: "RFC8949"
+ COSE: "RFC9052"
+ "COSE Sign": "RFC9052-CoseSign"
+ "COSE Header Parameters": "RFC9052-HeaderParameters"
+ "RFC9165 - CDDL Additional Controls": "RFC9165"
+ "text/plain;": "text/plain"
+ "text/markdown;": "CommonMark"
+ "text/html;": "HTML5"
+ "text/css;": "text/css"
+ "charset=utf-8": "RFC3629"
+ "charset=utf-8;": "RFC3629"
+ "template=handlebars": "Handlebars"
+ "application/schema+json": "JSON Schema-2020-12"
+ "application/cddl": "RFC8610"
+ "JSON Schema Draft 2020-12": "JSON Schema-2020-12"
+ Markdown: "CommonMark"
+ HTML: "HTML5"
+ "JSON Schema": "JSON Schema-2020-12"
+}
+
+all_aka_names: list.UniqueItems
+all_aka_names: list.Sort([
+ for k, _ in linkAKA {k},
+], list.Ascending)
+
+// Reports incompatible list length if we have a link name match an aka name.
+aka_not_in_names: []
+aka_not_in_names: [
+ for n in all_aka_names if list.Contains(all_link_names, n) {n},
+]
+
+all_link_and_aka_names: list.UniqueItems
+all_link_and_aka_names: list.Sort(
+ list.Concat(
+ [all_link_names, all_aka_names],
+ ), list.Ascending)
+
+#allLinkAndAKANames: or(all_link_and_aka_names)
diff --git a/specs/definitions/documentation/links.cue b/specs/definitions/documentation/links.cue
new file mode 100644
index 0000000000..6e2676455c
--- /dev/null
+++ b/specs/definitions/documentation/links.cue
@@ -0,0 +1,69 @@
+// External Documentation related definitions
+// Links
+package documentation
+
+import (
+ "list"
+ "strings"
+ "github.com/input-output-hk/catalyst-libs/specs/generic:url"
+)
+
+// A named Link to an external document, this would be encoded into markdown as:
+// [name]: url
+#docLinks: [string]: url.#absHttpsUrl
+
+links: #docLinks & {
+ "application/json": "https://www.iana.org/assignments/media-types/application/json"
+ "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor"
+ br: "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br"
+ "JSON Schema-draft7": "https://json-schema.org/draft-07"
+ "JSON Schema-2020-12": "https://json-schema.org/draft/2020-12"
+ RFC7932: "https://www.rfc-editor.org/rfc/rfc7932" // Brotli
+ RFC8259: "https://www.rfc-editor.org/rfc/rfc8259.html" // JSON
+ RFC8610: "https://www.rfc-editor.org/rfc/rfc8610" // CDDL
+ RFC8949: "https://www.rfc-editor.org/rfc/rfc8949.html" // CBOR
+ RFC9052: "https://datatracker.ietf.org/doc/html/rfc9052" // COSE
+ "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si" // COSE Multiple Signers
+ "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1" // COSE Header Parameters
+ RFC9165: "https://www.rfc-editor.org/rfc/rfc9165" // CDDL Additional Controls
+ CommonMark: "https://spec.commonmark.org/0.31.2/"
+ RFC3629: "https://datatracker.ietf.org/doc/html/rfc3629" // UTF-8
+ RFC3986: "https://datatracker.ietf.org/doc/html/rfc3986" // URI
+ RFC9562: "https://www.rfc-editor.org/rfc/rfc9562.html" // UUID
+ "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4" // UUID V4
+ "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7" // UUID V7
+ "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode" // CC BY 4.0
+ "IPFS-CID": "https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid" // IPFS Content Identifier
+ "CBOR-TAG-42": "https://github.com/ipld/cid-cbor/" // IPLD content identifiers (CIDs) in CBOR
+ "CBOR-TAG-37": "https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md" // UUID Tag for CBOR
+ "CBOR-LFD-ENCODING": "https://www.rfc-editor.org/rfc/rfc8949.html#section-4.2.3" // CBOR length-first core deterministic encoding requirements
+ Handlebars: "https://handlebarsjs.com/"
+ Mustache: "https://mustache.github.io/mustache.5.html"
+ HTML5: "https://html.spec.whatwg.org/multipage/syntax.html#syntax"
+ CSS: "https://www.w3.org/Style/CSS/"
+ "text/plain": "https://www.rfc-editor.org/rfc/rfc2046.html"
+ "text/css": "https://www.rfc-editor.org/rfc/rfc2318.html"
+}
+
+// Constrains the URLs being linked to be unique
+#uniqueLinkValues: list.UniqueItems
+#uniqueLinkValues: [...url.#absHttpsUrl] & [
+ for _, v in links {v},
+]
+
+all_links: list.UniqueItems
+all_links: [...url.#absHttpsUrl] & list.Sort([
+ for _, v in links {v},
+], list.Ascending)
+
+#allLinks: or(all_links)
+
+#linkName: string
+#linkName: strings.MinRunes(2)
+
+all_link_names: list.UniqueItems
+all_link_names: [...#linkName] & list.Sort([
+ for k, _ in links {k},
+], list.Ascending)
+
+#allLinkNames: or(all_link_names)
diff --git a/specs/definitions/form_template/choices.cue b/specs/definitions/form_template/choices.cue
new file mode 100644
index 0000000000..0c8a991c2d
--- /dev/null
+++ b/specs/definitions/form_template/choices.cue
@@ -0,0 +1,28 @@
+// Choices that can be made for a string field.
+package form_template
+
+import (
+ "list"
+)
+
+// Valid values for `format`
+_allFormats: list.UniqueItems
+_allFormats: list.Sort([
+ "uri",
+ "path",
+], list.Ascending)
+
+#formatChoices: or(_allFormats)
+
+// Valid values for `contentMediaType`
+_allContentMediaTypes: list.UniqueItems
+_allContentMediaTypes: list.Sort([
+ "text/plain",
+ "text/plain; template=handlebars",
+ "text/markdown",
+ "text/markdown; template=handlebars",
+ "text/html",
+ "text/html; template=handlebars",
+], list.Ascending)
+
+#contentMediaTypeChoices: or(_allContentMediaTypes)
diff --git a/specs/definitions/form_template/dictionary.cue b/specs/definitions/form_template/dictionary.cue
new file mode 100644
index 0000000000..dad7de9b05
--- /dev/null
+++ b/specs/definitions/form_template/dictionary.cue
@@ -0,0 +1,20 @@
+// Template Json Schema Definitions Dictionary
+//
+// All known and supported Json Schema definitions,
+// and their parameters and documentation so that
+// a dictionary document and the definitions themselves
+// can be generated.
+package form_template
+
+// Types of a Metadata Fields
+#formTemplateElementNames: or([
+ for k, _ in dictionary {k},
+])
+
+// Definitions for all defined template schema field types.
+formTemplate: #formTemplate & {}
+
+// Types of a Metadata Fields
+#formTemplateElementNames: or([
+ for k, _ in dictionary {k},
+])
diff --git a/specs/definitions/form_template/field.cue b/specs/definitions/form_template/field.cue
new file mode 100644
index 0000000000..ad42a6e406
--- /dev/null
+++ b/specs/definitions/form_template/field.cue
@@ -0,0 +1,76 @@
+// Individual Field Definition.
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+// Schema Definition for the Form Element.
+// This appears in the `definitions` section of the Form Template
+// exactly as defined here.
+// UI *MUST* not process definitions, its only use is to enforce validation.
+// UI/UX *MUST* interpret the name of the Form Element via `$ref` only.
+// The values in the definition can inform creation of a valid UI widget
+// which matches the Form Element, but that *MUST* not be dynamic.
+#formElementDefinition: {
+ // The underlying json type of the Form Element.
+ type: #fieldType
+
+ // IF true, the Form Element is not a data entry field.
+ // Depending on the Form Element, it may not be displayed by the form.
+ // but MUST be present in the encoded json form data.but can be used for presentation and formatting.
+ readOnly?: true
+
+ // Form Elements which hold other form elements
+ if type == "object" {
+ // MUST not allow undefined properties
+ additionalProperties: false // IF false, can not define extra fields.
+ // MAY list properties as non optional by including them in a `required` list.
+ // properties not included in this list are optional.
+ // may not be entered by the user into the form, and if not entered
+ // should be excluded (or defaulted as required) from the
+ // forms json data.
+ required?: [...string]
+ }
+
+ // Form Elements which are a list of other Form Elements
+ if type == "array" {
+ // The type of Form Elements in the list.
+ items: #formElementDefinition
+ // Are the Elements Unique?
+ uniqueItems: false | *true
+ }
+
+ if type == "string" {
+ format?: #formatChoices
+ contentMediaType?: #contentMediaTypeChoices
+ pattern?: regex.#regex
+ minLength?: int // Only to enforce that the field can not be empty (such as when used in lists)
+ }
+
+}
+
+// An Element which can be present in a Templated Form.
+// Elements define both the data validation and the expected
+// type of data entry UI expected of the Element.
+// This allows JsonSchema to express both Validation and Presentation without
+// requiring an extensive new DSL to be created.
+#formElement: {
+ // Documentation
+ description: string
+
+ // MAPS 1:1 to the `definitions` section within JSON Schema draft 7.
+ definition: #formElementDefinition
+
+ // If this field type must appear only as a child of another field type.
+ // If `parent` is NOT defined, then the `parent` is the root of the template.
+ // The root object of the template is defined with the special string `{}`
+ //
+ parent: #formTemplateElementNames | *"{}"
+
+ // The parameters supported by a particular field definition
+ parameters: _allParameters
+}
+
+#formTemplate: [string]: #formElement
diff --git a/specs/definitions/form_template/fields/drop_down_single_select.cue b/specs/definitions/form_template/fields/drop_down_single_select.cue
new file mode 100644
index 0000000000..7744d4793f
--- /dev/null
+++ b/specs/definitions/form_template/fields/drop_down_single_select.cue
@@ -0,0 +1,31 @@
+// Radio Button selection from a list of text options.
+
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ dropDownSingleSelect: {
+ description: """
+ UI - Drop Down Selection of a single entry from the defined enum.
+
+ Select one option from a selector styled as a dropdown menu.
+ Only one choice is allowed.
+ """
+ parent: "section"
+ definition: {
+ type: "string"
+ contentMediaType: "text/plain"
+ pattern: regex.def.singleLine.pattern
+ }
+ parameters: {
+ title: {}
+ description: {}
+ enum: {}
+ "x-guidance": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/multi_line_text_entry.cue b/specs/definitions/form_template/fields/multi_line_text_entry.cue
new file mode 100644
index 0000000000..f9db14d945
--- /dev/null
+++ b/specs/definitions/form_template/fields/multi_line_text_entry.cue
@@ -0,0 +1,33 @@
+// Single Line Text Entry
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ multiLineTextEntry: {
+ description: """
+ UI - One or more Lines of text entry.
+ Line breaks, and special characters are allowed.
+ Special formatted markup, such as Markdown are not allowed.
+ Enter multiple lines of plain text. You can use line breaks but no special formatting.
+ """
+ parent: "section"
+
+ definition: {
+ type: "string"
+ contentMediaType: "text/plain"
+ pattern: regex.def.multiLine.pattern
+ }
+ parameters: {
+ title: {}
+ description: {}
+ minLength: {}
+ maxLength: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/multi_line_text_entry_markdown.cue b/specs/definitions/form_template/fields/multi_line_text_entry_markdown.cue
new file mode 100644
index 0000000000..5a231e9a18
--- /dev/null
+++ b/specs/definitions/form_template/fields/multi_line_text_entry_markdown.cue
@@ -0,0 +1,35 @@
+// Single Line Text Entry
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ multiLineTextEntryMarkdown: {
+ description: """
+ UI - Multiline text entry with Markdown content.
+ Use Markdown formatting for rich text.
+ Markdown formatting is as defined by CommonMark.
+
+ The following Markdown Extensions are also supported:
+
+ * None
+ """
+ definition: {
+ type: "string"
+ contentMediaType: "text/markdown"
+ pattern: regex.def.multiLine.pattern
+ }
+ parent: "section"
+ parameters: {
+ title: {}
+ description: {}
+ minLength: {}
+ maxLength: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/multi_line_text_entry_markdown_list.cue b/specs/definitions/form_template/fields/multi_line_text_entry_markdown_list.cue
new file mode 100644
index 0000000000..c680ad79d6
--- /dev/null
+++ b/specs/definitions/form_template/fields/multi_line_text_entry_markdown_list.cue
@@ -0,0 +1,35 @@
+// Single Line Text Entry List
+
+package form_template
+
+dictionary: #formTemplate & {
+ multiLineTextEntryListMarkdown: {
+ description: """
+ UI - A Growable List of markdown formatted text fields.
+ Each entry is a multiline markdown formatted string.
+ Markdown Formatting, line breaks, or special characters are allowed.
+ Add multiple text entries.
+ Each entry should be unique.
+ """
+ definition: {
+ type: "array"
+ items: dictionary.multiLineTextEntryMarkdown.definition
+ items: minLength: 1
+ uniqueItems: true
+ }
+ parent: "section"
+ parameters: {
+ title: {}
+ description: {}
+ default: {
+ description: "Default Array of text can be supplied."
+ required: "optional"
+ }
+ minItems: {}
+ maxItems: {}
+ contains: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/multi_select.cue b/specs/definitions/form_template/fields/multi_select.cue
new file mode 100644
index 0000000000..82fcf100d0
--- /dev/null
+++ b/specs/definitions/form_template/fields/multi_select.cue
@@ -0,0 +1,34 @@
+// Radio Button selection from a list of text options.
+
+package form_template
+
+dictionary: #formTemplate & {
+ multiSelect: {
+ description: """
+ UI - Multiselect from the given items.
+
+ Select multiple options from the dropdown menu.
+ Multiple choices are allowed.
+ All choices MUST be unique.
+ """
+ parent: "section"
+
+ definition: {
+ type: "array"
+ uniqueItems: true
+ items: dictionary.singleLineTextEntry.definition
+ }
+ parameters: {
+ title: {}
+ description: {}
+ default: {
+ description: "Default selections can be supplied."
+ required: "optional"
+ }
+ minItems: {}
+ maxItems: {}
+ contains: {}
+ "x-guidance": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/radio_button_select.cue b/specs/definitions/form_template/fields/radio_button_select.cue
new file mode 100644
index 0000000000..f45547c9a4
--- /dev/null
+++ b/specs/definitions/form_template/fields/radio_button_select.cue
@@ -0,0 +1,32 @@
+// Radio Button selection from a list of text options.
+
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ radioButtonSelect: {
+ description: """
+ UI - Radio Button Selection.
+
+ Select one option from a list of text options.
+ Selector is styled as a set of Radio Buttons.
+ """
+ parent: "section"
+
+ definition: {
+ type: "string"
+ contentMediaType: "text/plain"
+ pattern: regex.def.singleLine.pattern
+ }
+ parameters: {
+ title: {}
+ description: {}
+ enum: {}
+ "x-guidance": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/schema_reference.cue b/specs/definitions/form_template/fields/schema_reference.cue
new file mode 100644
index 0000000000..48ab3c1daf
--- /dev/null
+++ b/specs/definitions/form_template/fields/schema_reference.cue
@@ -0,0 +1,27 @@
+// Schema Reference - Not used in any UI
+package form_template
+
+dictionary: #formTemplate & {
+ schemaReferenceNonUI: {
+ description: """
+ Enforces the json document having a proper reference to the schema.
+ """
+ parent: "section"
+
+ definition: {
+ type: "string"
+ readOnly: true
+ }
+
+ parameters: {
+ default: {
+ description: "The path that is defined to find the matching json schema."
+ required: "yes"
+ }
+ const: {
+ description: "The path must always be this value. **MUST** match `default`."
+ required: "yes"
+ }
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/section.cue b/specs/definitions/form_template/fields/section.cue
new file mode 100644
index 0000000000..97105a3044
--- /dev/null
+++ b/specs/definitions/form_template/fields/section.cue
@@ -0,0 +1,31 @@
+// Document Segment
+//
+// Segment -
+// Section -
+// Topic -
+package form_template
+
+dictionary: #formTemplate & {
+ section: {
+ description: """
+ UI - Logical Document Sub-Section Break.
+ Subsections containing specific details about the proposal.
+ """
+ parent: "segment"
+ definition: type: "object"
+ parameters: {
+ title: {
+ description: "The title of the section."
+ required: "yes"
+ }
+ description: description: "The displayable description attached to the section. Markdown formatted contents."
+ properties: description: "The sub fields of the section."
+ required: {
+ description: "Which fields MUST appear in the segment."
+ required: "optional"
+ }
+ "x-icon": {}
+ "x-order": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/segment.cue b/specs/definitions/form_template/fields/segment.cue
new file mode 100644
index 0000000000..3af9472bb4
--- /dev/null
+++ b/specs/definitions/form_template/fields/segment.cue
@@ -0,0 +1,29 @@
+// Document Segment
+//
+// Segment -
+// Section -
+// Topic -
+package form_template
+
+dictionary: #formTemplate & {
+ segment: {
+ description: """
+ Logical Document Section - Grouping Only - Highest Level Group
+ "x-note": "
+ Major sections of the proposal. Each segment contains sections of information grouped together.
+ "
+ """
+ definition: type: "object"
+ parameters: {
+ title: description: "The title of the segment."
+ description: description: "The displayable description attached to the segment. Markdown formatted contents."
+ properties: description: "The sub fields of the segment."
+ required: {
+ description: "Which fields MUST appear in the segment."
+ required: "optional"
+ }
+ "x-icon": {}
+ "x-order": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/single_grouped_tag_selector.cue b/specs/definitions/form_template/fields/single_grouped_tag_selector.cue
new file mode 100644
index 0000000000..b1f18645e5
--- /dev/null
+++ b/specs/definitions/form_template/fields/single_grouped_tag_selector.cue
@@ -0,0 +1,49 @@
+// Tag Input
+package form_template
+
+dictionary: #formTemplate & {
+
+ singleGroupedTagSelector: {
+ description: """
+ UI - A selector where a top level group selection, allows a single choice from a list of tags.
+ Select one option from the dropdown menu.
+ Only one choice is allowed.
+
+ The contents of the `singleGroupedTagSelector` *MUST* have the following format:
+
+ ```json
+ "oneOf": [
+ {
+ "properties": {
+ "group": {
+ "$ref": "#/definitions/tagGroup",
+ "const": "Governance"
+ },
+ "tag": {
+ "$ref": "#/definitions/tagSelection",
+ "enum": [
+ "Governance",
+ "DAO"
+ ]
+ }
+ }
+ },
+ ```
+ """
+ parent: "section"
+
+ definition: {
+ type: "object"
+ required: [
+ "group",
+ "tag",
+ ]
+ }
+ parameters: {
+ title: {}
+ description: {}
+ "x-guidance": {}
+ oneOf_groupedTags: {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/single_line_https_url_entry.cue b/specs/definitions/form_template/fields/single_line_https_url_entry.cue
new file mode 100644
index 0000000000..4d3cc7118e
--- /dev/null
+++ b/specs/definitions/form_template/fields/single_line_https_url_entry.cue
@@ -0,0 +1,34 @@
+// Single Line HTTPS URL Text Entry
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ singleLineHttpsURLEntry: {
+ description: """
+ UI - Single Line text entry for HTTPS Urls.
+ "x-note":
+ Must start with 'https://' and is followed by one or more
+ non-whitespace characters, ending at the end of the string.
+
+ """
+ parent: "section"
+
+ definition: {
+ type: "string"
+ format: "uri"
+ pattern: regex.def.httpsUrl.pattern
+ }
+ parameters: {
+ title: {}
+ description: {}
+ minLength: {}
+ maxLength: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/single_line_https_url_entry_list.cue b/specs/definitions/form_template/fields/single_line_https_url_entry_list.cue
new file mode 100644
index 0000000000..1c1c484380
--- /dev/null
+++ b/specs/definitions/form_template/fields/single_line_https_url_entry_list.cue
@@ -0,0 +1,36 @@
+// Single Line Text Entry List
+
+package form_template
+
+dictionary: #formTemplate & {
+ singleLineHttpsURLEntryList: {
+ description: """
+ UI - A Growable List of single line text
+ A single line of text.
+ No formatting, markup, line breaks, or special characters are allowed.
+ Add multiple single-line text entries.
+ Each entry should be unique.
+ """
+ parent: "section"
+
+ definition: {
+ type: "array"
+ items: dictionary.singleLineHttpsURLEntry.definition
+ items: minLength: 1
+ uniqueItems: true
+ }
+ parameters: {
+ title: {}
+ description: {}
+ default: {
+ description: "Default Array of URLs can be supplied."
+ required: "optional"
+ }
+ minItems: {}
+ maxItems: {}
+ contains: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/single_line_text_entry.cue b/specs/definitions/form_template/fields/single_line_text_entry.cue
new file mode 100644
index 0000000000..cd9a0899ee
--- /dev/null
+++ b/specs/definitions/form_template/fields/single_line_text_entry.cue
@@ -0,0 +1,31 @@
+// Single Line Text Entry
+package form_template
+
+import (
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+
+)
+
+dictionary: #formTemplate & {
+ singleLineTextEntry: {
+ description: """
+ UI - Single Line text entry without any markup or rich text capability.
+ A single line of text.
+ No formatting, markup, line breaks, or special characters are allowed.
+ """
+ parent: "section"
+
+ definition: {
+ type: "string"
+ pattern: regex.def.singleLine.pattern
+ }
+ parameters: {
+ title: {}
+ description: {}
+ minLength: {}
+ maxLength: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/fields/single_line_text_entry_list.cue b/specs/definitions/form_template/fields/single_line_text_entry_list.cue
new file mode 100644
index 0000000000..961d421cf5
--- /dev/null
+++ b/specs/definitions/form_template/fields/single_line_text_entry_list.cue
@@ -0,0 +1,36 @@
+// Single Line Text Entry List
+
+package form_template
+
+dictionary: #formTemplate & {
+ singleLineTextEntryList: {
+ description: """
+ UI - A Growable List of single line text
+ A single line of text.
+ No formatting, markup, line breaks, or special characters are allowed.
+ Add multiple single-line text entries.
+ Each entry should be unique.
+ """
+ parent: "section"
+
+ definition: {
+ type: "array"
+ items: dictionary.singleLineTextEntry.definition
+ items: minLength: 1
+ uniqueItems: true
+ }
+ parameters: {
+ title: {}
+ description: {}
+ default: {
+ description: "Default Array of text can be supplied."
+ required: "optional"
+ }
+ minItems: {}
+ maxItems: {}
+ contains: {}
+ "x-guidance": {}
+ "x-placeholder": {}
+ }
+ }
+}
diff --git a/specs/definitions/form_template/icon_choices.cue b/specs/definitions/form_template/icon_choices.cue
new file mode 100644
index 0000000000..dfc4b77de8
--- /dev/null
+++ b/specs/definitions/form_template/icon_choices.cue
@@ -0,0 +1,283 @@
+// List of all valid ICON choices.
+// The UI is free to render Icons or not and render them in its own style.
+// However, Icons not listed here are not supported.
+package form_template
+
+import (
+ "list"
+)
+
+_allIcons: list.UniqueItems
+_allIcons: list.Sort([
+ "academic-cap",
+ "ada",
+ "adjustments",
+ "'all spaces menu-1'",
+ "'all spaces menu'",
+ "annotation",
+ "archive",
+ "arrow-circle-down",
+ "arrow-circle-left",
+ "arrow-circle-right",
+ "arrow-circle-up",
+ "arrow-down",
+ "arrow-left",
+ "arrow-narrow-down",
+ "arrow-narrow-left",
+ "arrow-narrow-right",
+ "arrow-narrow-up",
+ "arrow-right",
+ "arrow-triangle-down",
+ "arrow-triangle-up",
+ "arrow-up",
+ "arrows-expand",
+ "at-symbol",
+ "avatar_placeholder",
+ "backspace",
+ "badge-check",
+ "ban",
+ "beaker",
+ "bell",
+ "book-open",
+ "bookmark-alt",
+ "bookmark",
+ "bottom-main-content",
+ "bottom-rail-toggle-1",
+ "bottom-rail-toggle",
+ "briefcase",
+ "cake",
+ "calculator",
+ "calendar",
+ "camera",
+ "cash",
+ "chart-bar",
+ "chart-pie",
+ "chart-square-bar",
+ "chat-alt-2",
+ "chat-alt",
+ "chat",
+ "check-circle",
+ "check",
+ "chevron-double-down",
+ "chevron-double-left",
+ "chevron-double-right",
+ "chevron-double-up",
+ "chevron-down-1",
+ "chevron-down",
+ "chevron-left",
+ "chevron-right",
+ "chevron-up",
+ "chip",
+ "clipboard-check",
+ "clipboard-copy",
+ "clipboard-list",
+ "clipboard",
+ "clock",
+ "cloud-download",
+ "cloud-upload",
+ "cloud",
+ "code",
+ "cog-gear",
+ "collection",
+ "color-swatch",
+ "credit-card",
+ "cube-transparent",
+ "cube",
+ "currency-bangladeshi",
+ "currency-dollar",
+ "currency-euro",
+ "currency-pound",
+ "currency-rupee",
+ "currency-yen",
+ "cursor-click",
+ "curved-arrow-right",
+ "database",
+ "desktop-computer",
+ "device-mobile",
+ "device-tablet",
+ "document-add",
+ "document-remove",
+ "document-report",
+ "document-search",
+ "document-text",
+ "document",
+ "dots-circle-horizontal",
+ "dots-horizontal",
+ "dots-vertical",
+ "double_check",
+ "download",
+ "duplicate",
+ "emoji-happy",
+ "emoji-sad",
+ "exclamation-circle",
+ "exclamation",
+ "external-link",
+ "eye-off",
+ "eye",
+ "facebook",
+ "fast-forward",
+ "film",
+ "filter",
+ "finger-print",
+ "fire",
+ "flag",
+ "folder-add",
+ "folder-download",
+ "folder-open",
+ "folder-remove",
+ "folder",
+ "fund",
+ "gift",
+ "globe-alt",
+ "globe",
+ "hand",
+ "hashtag",
+ "heart",
+ "home",
+ "icon-user-remove",
+ "identification",
+ "inbox-in",
+ "inbox",
+ "information-circle",
+ "key",
+ "left-rail-toggle",
+ "library",
+ "light-bulb",
+ "lightning-bolt",
+ "link",
+ "linkedin",
+ "location-marker",
+ "lock-closed",
+ "lock-open",
+ "logout-1",
+ "logout",
+ "mail-open",
+ "mail",
+ "map",
+ "maximize-toggle",
+ "menu-alt-1",
+ "menu-alt-2",
+ "menu-alt-3",
+ "menu-alt-4",
+ "menu",
+ "microphone",
+ "minimize-toggle",
+ "minus-circle",
+ "minus",
+ "moon",
+ "move-item",
+ "music-note",
+ "newspaper",
+ "node-closed",
+ "node-line-end",
+ "node-line",
+ "node-open",
+ "office-building",
+ "paper-airplane",
+ "paper-clip",
+ "pause",
+ "pencil-alt",
+ "pencil",
+ "phone-incoming",
+ "phone-missed-call",
+ "phone-outgoing",
+ "phone",
+ "photograph",
+ "play",
+ "plus",
+ "plus_circle_filled",
+ "plus_circle_outlined",
+ "presentation-chart-bar",
+ "presentation-chart-line",
+ "printer",
+ "progress-track-warning",
+ "puzzle",
+ "qrcode",
+ "question-mark-circle",
+ "receipt-refund",
+ "receipt-tax",
+ "reddit",
+ "refresh",
+ "reply",
+ "rewind",
+ "right-rail-toggle",
+ "rss",
+ "rt_bold",
+ "rt_decrease_indent",
+ "rt_heading",
+ "rt_increase_indent",
+ "rt_italic",
+ "rt_ordered_list",
+ "rt_unordered_list",
+ "save-as",
+ "save",
+ "scale",
+ "scissors",
+ "search-circle",
+ "search",
+ "selector",
+ "send-airplane",
+ "server",
+ "share",
+ "shield-check",
+ "shield-exclamation",
+ "shopping-bag",
+ "shopping-cart",
+ "sm-view-grid-add",
+ "sort-ascending",
+ "sort-descending",
+ "sparkles",
+ "speakerphone",
+ "star_filled",
+ "star_outlined",
+ "status-offline",
+ "status-online",
+ "stop",
+ "summary",
+ "sun",
+ "support",
+ "switch-horizontal",
+ "switch-vertical",
+ "table",
+ "tag",
+ "template",
+ "terminal",
+ "thumb-down",
+ "thumb-up",
+ "ticket",
+ "top-bar-filled",
+ "top-bar",
+ "translate",
+ "trash",
+ "trending-down",
+ "trending-up",
+ "truck",
+ "unlink",
+ "upload",
+ "user-add",
+ "user-circle",
+ "user-group",
+ "user",
+ "users",
+ "variable",
+ "video-camera",
+ "view-boards",
+ "view-grid",
+ "view-list",
+ "volume-off",
+ "volume-up",
+ "vote",
+ "wallet",
+ "wifi",
+ "x-circle",
+ "x",
+ "xTwitter",
+ "zoom-in",
+ "zoom-out",
+], list.Ascending)
+
+#iconChoices: or(_allIcons)
+
+// test
+// good_icon: #iconChoices & "tag"
+// bad_icon: #iconChoices & "tags"
diff --git a/specs/definitions/form_template/parameters.cue b/specs/definitions/form_template/parameters.cue
new file mode 100644
index 0000000000..ab877972b0
--- /dev/null
+++ b/specs/definitions/form_template/parameters.cue
@@ -0,0 +1,182 @@
+// Definitions of the field parameters within a template.
+package form_template
+
+import (
+ "list"
+ "regexp"
+ "github.com/input-output-hk/catalyst-libs/specs/generic:optional"
+)
+
+// Supported field `type`
+// Same as Json Schema minus `null`
+#fieldType: "array" |
+ "array" |
+ "boolean" |
+ "integer" |
+ "number" |
+ "object" |
+ *"string"
+
+// List of properties allowed in the `property` field of `jsonParameter`
+#properties: "oneOf"
+
+#parameter: {
+ property?: #properties // Name of the property, IF its not the same as the parameter.
+ description: string
+ required: optional.#field
+
+ // The following constrain the value of the parameter
+ // within a template.
+ // They DO NOT constrain the value of the field element
+ // The parameter relates to.
+ // The Field element is constrained by the parameters value.
+ // Their purpose is to assist creation of templates to set
+ // the appropriate form element parameters within the template properties.
+ type: #fieldType
+ items?: #parameter
+ choices?: list.UniqueItems
+
+ // All parameters when defined require an example of their use
+ // within the
+ example?: _ // Set to `null` ONLY when the example is autogenerated.
+
+ // If the parameter is a `string` it can be constrained with the following
+ // options.
+ if type == "string" {
+ format?: #formatChoices
+ contentMediaType?: #contentMediaTypeChoices
+ pattern?: regexp.Valid
+ minLength?: int // Only to enforce that the field can not be empty (such as when used in lists)
+ choices?: [...string]
+ }
+
+ // If the parameter is a `integer` it can be constrained with the following
+ // options.
+ if type == "integer" {
+ choices?: [...int]
+ minimum?: int
+ maximum?: int
+ }
+
+}
+
+// The parameters supported by a particular field definition
+_allParameters: {
+ title?: #parameter & {
+ description: _ | *"The label attached to the field."
+ required: "yes"
+ }
+ description?: #parameter & {
+ description: _ | *"The description of the field presented during data entry."
+ required: "optional"
+ }
+ required?: #parameter & {
+ required: _ | *"optional"
+ }
+ default?: #parameter & {
+ required: _ | *"yes"
+ }
+ const?: #parameter & {
+ required: _ | *"yes"
+ }
+ properties?: #parameter & {
+ required: _ | *"yes"
+ description: _ | *"All sub fields contained in the object."
+ required: "yes"
+ //example: null // Example properties are generated from child properties.
+ }
+ minLength?: #parameter & {
+ type: "integer"
+ description: _ | *"Minimum number of characters allowed in the field."
+ required: "optional"
+ }
+ maxLength?: #parameter & {
+ type: "integer"
+ description: _ | *"Maximum number of characters allowed in the field."
+ required: "yes"
+ }
+ enum?: #parameter & {
+ type: "array"
+ items: {
+ description: "An element of the Enum."
+ type: "string"
+ }
+ description: _ | *"An array of string to select from."
+ required: "yes"
+ }
+ minItems?: #parameter & {
+ type: "integer"
+ description: _ | *#"An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword."#
+ required: "optional"
+ }
+ maxItems?: #parameter & {
+ type: "integer"
+ description: _ | *#"An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword."#
+ required: "yes"
+ }
+ contains?: #parameter & {
+ type: "array"
+ items: {
+ description: "An individual Choice."
+ type: "string"
+ }
+ description: _ | *"The choices the multi select can contain."
+ required: "yes"
+ }
+ oneOf_groupedTags?: #parameter & {
+ property: "oneOf"
+ type: "array"
+ items: {
+ description: """
+ An array of grouped tag objects, of which one can be selected.
+ Each object *MUST* have the form:
+
+ ```json
+ "properties": {
+ "group": {
+ "$ref": "#/definitions/tagGroup",
+ "const":
+ },
+ "tag": {
+ "$ref": "#/definitions/tagSelection",
+ "enum": [
+ ,
+ ,
+ ...
+ ]
+ }
+ }
+ ```
+ """
+ type: "object"
+ }
+ description: "A set of tags with a group selector."
+ }
+ "x-guidance"?: #parameter & {
+ description: _ | *"Long form Markdown formatted description to give guidance about how the field is to be completed."
+ required: "optional"
+ }
+ "x-placeholder"?: #parameter & {
+ description: _ | *"Placeholder text to display inside the field if it is empty."
+ required: "optional"
+ }
+ "x-icon"?: #parameter & {
+ description: _ | *"The name of the Icon to display with the field."
+ required: "optional"
+ choices: _allIcons
+ }
+ "x-order"?: #parameter & {
+ required: "yes"
+ description: """
+ The ordering of the properties to be enforced when displayed.
+ Any field not listed here will get displayed in an arbitrary order.
+ """
+ }
+ "x-subsection"?: #parameter & {
+ required: "optional"
+ type: bool
+ description: """
+ TODO: Explain what this parameter does...
+ """
+ }
+}
diff --git a/specs/generic/date.cue b/specs/definitions/generic/date.cue
similarity index 100%
rename from specs/generic/date.cue
rename to specs/definitions/generic/date.cue
diff --git a/specs/generic/optional.cue b/specs/definitions/generic/optional.cue
similarity index 100%
rename from specs/generic/optional.cue
rename to specs/definitions/generic/optional.cue
diff --git a/specs/definitions/generic/url.cue b/specs/definitions/generic/url.cue
new file mode 100644
index 0000000000..fec80fa13f
--- /dev/null
+++ b/specs/definitions/generic/url.cue
@@ -0,0 +1,15 @@
+package url
+
+import (
+ "net"
+ "github.com/input-output-hk/catalyst-libs/specs/regex"
+)
+
+#absUrl: string
+#absUrl: net.AbsURL
+
+#absHttpsUrl: #absUrl
+#absHttpsUrl: =~regex.def.httpsUrl.pattern
+
+#relativeUrl: string
+#relativeUrl: net.URL
diff --git a/specs/generic/uuid.cue b/specs/definitions/generic/uuid.cue
similarity index 100%
rename from specs/generic/uuid.cue
rename to specs/definitions/generic/uuid.cue
diff --git a/specs/definitions/media_types/content.cue b/specs/definitions/media_types/content.cue
new file mode 100644
index 0000000000..0650303f18
--- /dev/null
+++ b/specs/definitions/media_types/content.cue
@@ -0,0 +1,135 @@
+// Content and Encoding Types
+package media_types
+
+import (
+ "list"
+)
+
+// Content Type name : Description
+#contentTypes: {
+ [string]: {
+ description: string // description of the content type
+ coap_type?: int
+ }
+}
+
+_plaintext_description: """
+ Plain Text with no markup or special formatting.
+ Multiline Plain Text *MUST* always interpret `\n`
+ as a hard line break.
+ """
+
+_markdown_description: """
+ Formatted text using Markdown for rich text.
+ Markdown formatting is as defined by CommonMark.
+
+ IF the document includes HTML, then HTML5 syntax only is supported.
+
+ The following Markdown Extensions are also supported:
+
+ * None
+ """
+
+_html_description: """
+ Formatted text using HTML5 markup for rich text.
+ Only HTML5 syntax is supported.
+ """
+
+_css_description: """
+ CSS Content used for styling HTML.
+ CSS should use the least set of features possible to achieve
+ the desired presentation to ensure the broadest compatibility.
+ """
+
+_handlebars_template_description: """
+ The text includes Handlebars type template fields that need
+ processing and replacement prior to display.
+ """
+
+contentTypes: #contentTypes & {
+ "application/json": {
+ description: "JSON Document"
+ coap_type: 50
+ }
+ "application/schema+json": description: """
+ A JSON Schema Draft 2020-12 Document.
+
+ Note:
+
+ * This is currently an unofficial media type.
+ """
+ "application/cbor": {
+ description: "An RFC8949 Binary CBOR Encoded Document."
+ coap_type: 60
+ }
+ "application/cddl": description: """
+ A CDDL Document.
+
+ Note:
+
+ * This is an unofficial media type
+ * RFC9165 Additional Control Operators for CDDL are supported.
+ * Must not have Modules, schema must be self-contained.
+ """
+ "text/plain; charset=utf-8": {
+ description: """
+ \(_plaintext_description)
+ """
+ coap_type: 0
+ }
+ "text/plain; charset=utf-8; template=handlebars": description: """
+ \(_plaintext_description)
+
+ \(_handlebars_template_description)
+ """
+ "text/markdown; charset=utf-8": description: """
+ \(_markdown_description)
+ """
+ "text/markdown; charset=utf-8; template=handlebars": description: """
+ \(_markdown_description)
+
+ \(_handlebars_template_description)
+ """
+ "text/html; charset=utf-8": description: """
+ \(_html_description)
+ """
+ "text/html; charset=utf-8; template=handlebars": description: """
+ \(_html_description)
+
+ \(_handlebars_template_description)
+ """
+ "text/css; charset=utf-8": {
+ description: """
+ \(_css_description)
+ """
+ coap_type: 20000
+ }
+ "text/css; charset=utf-8; template=handlebars": description: """
+ \(_css_description)
+
+ \(_handlebars_template_description)
+ """
+}
+
+allContentTypes: list.Sort([
+ for k, _ in contentTypes {k},
+], list.Ascending)
+
+#contentType: or(allContentTypes)
+
+coapTypes: {
+ for k, v in contentTypes
+ if v.coap_type != _|_ {
+ "\(v.coap_type)": k
+ }
+}
+
+allCoapTypes: list.UniqueItems
+allCoapTypes: list.Sort([
+ for _, v in contentTypes if v.coap_type != _|_ {v.coap_type},
+], list.Ascending)
+
+#allCoapTypes: or(allCoapTypes)
+
+allCoapTypesStr: [...string]
+allCoapTypesStr: [for v in allCoapTypes {"\(v)"}]
diff --git a/specs/definitions/media_types/encoding.cue b/specs/definitions/media_types/encoding.cue
new file mode 100644
index 0000000000..c813a241ed
--- /dev/null
+++ b/specs/definitions/media_types/encoding.cue
@@ -0,0 +1,18 @@
+// Content and Encoding Types
+package media_types
+
+import (
+ "list"
+)
+
+// Content Encoding Type name : Description
+encodingTypes: {
+ [string]: {
+ description: string // description of the content type
+ }
+}
+encodingTypes: br: description: "BROTLI Compression"
+
+allContentEncoding: list.Sort([
+ for k, _ in encodingTypes {k},
+], list.Ascending)
diff --git a/specs/definitions/regex/def.cue b/specs/definitions/regex/def.cue
new file mode 100644
index 0000000000..37b660e6b2
--- /dev/null
+++ b/specs/definitions/regex/def.cue
@@ -0,0 +1,41 @@
+// Regex Definitions
+package regex
+
+def: #def & {
+ singleLine: {
+ pattern: #"^[^\n]*$"#
+ description: "Single Line of Text"
+ }
+ multiLine: {
+ pattern: #"^[\S\s]*$"#
+ description: "Multiline Text"
+ }
+ httpsUrl: {
+ pattern: #"^https://[^\s]+$"#
+ description: "A URL that must begin with https://"
+ }
+}
+
+// Every definition above MUST have at least one test below
+// for the positive and negative match.
+positive_match: true
+
+positive_match: "" =~ def.singleLine.pattern
+positive_match: "single line" =~ def.singleLine.pattern
+
+positive_match: "single line" =~ def.multiLine.pattern
+positive_match: "multi\nline" =~ def.multiLine.pattern
+positive_match: "" =~ def.multiLine.pattern
+
+positive_match: "https://www.iana.org/assignments" =~ def.httpsUrl.pattern
+
+// Negative match (where possible to test)
+negative_match: false
+
+negative_match: "multi\nline" =~ def.singleLine.pattern
+
+// No negative multiline regex cases. Regex too simple.
+
+negative_match: "" =~ def.httpsUrl.pattern
+negative_match: "not a url" =~ def.httpsUrl.pattern
+negative_match: "http://www.iana.org/assignments" =~ def.httpsUrl.pattern
diff --git a/specs/definitions/regex/regex.cue b/specs/definitions/regex/regex.cue
new file mode 100644
index 0000000000..049b6c6195
--- /dev/null
+++ b/specs/definitions/regex/regex.cue
@@ -0,0 +1,14 @@
+// Regex Definitions
+package regex
+
+import (
+ "regexp"
+)
+
+#regex: string
+#regex: regexp.Valid
+
+#def: [string]: {
+ pattern: #regex
+ description: string
+}
diff --git a/specs/signed_docs/authors_copyright.cue b/specs/definitions/signed_docs/authors_copyright.cue
similarity index 79%
rename from specs/signed_docs/authors_copyright.cue
rename to specs/definitions/signed_docs/authors_copyright.cue
index c354a5b10e..2d9a8314d8 100644
--- a/specs/signed_docs/authors_copyright.cue
+++ b/specs/definitions/signed_docs/authors_copyright.cue
@@ -60,5 +60,16 @@ copyright: #copyrightNotice & {
* Use generalized parameters.
"""
},
+ {
+ version: "0.04"
+ modified: "2025-05-30"
+ changes: """
+ * Improve and make document serialization more repeatable, and stricter.
+ * TODO: Define Systems parameters
+ * TODO: Define DReps documents.
+ * TODO: Define Proposer Profiles.
+ * TODO: Define Role 0 Profile.
+ """
+ },
]
}
diff --git a/specs/signed_docs/cddl_defs.cue b/specs/definitions/signed_docs/cddl_defs.cue
similarity index 59%
rename from specs/signed_docs/cddl_defs.cue
rename to specs/definitions/signed_docs/cddl_defs.cue
index 77915ed529..014872fb44 100644
--- a/specs/signed_docs/cddl_defs.cue
+++ b/specs/definitions/signed_docs/cddl_defs.cue
@@ -14,61 +14,61 @@ package signed_docs
}
cddlDefinitions: #cddlDefinitions & {
- "uuid_v7": {
+ uuid_v7: {
def: "#6.37(bytes .size 16)"
description: """
Version 7 UUID
- See: \(documentationLinks."RFC9562-V7")
- \(documentationLinks."CBOR-TAG-37")
+ See: \(documentation.links."RFC9562-V7")
+ \(documentation.links."CBOR-TAG-37")
"""
comment: "UUIDv7"
}
- "uuid_v4": {
+ uuid_v4: {
def: "#6.37(bytes .size 16)"
description: """
Version 4 UUID
- See: \(documentationLinks."RFC9562-V4")
- \(documentationLinks."CBOR-TAG-37")
+ See: \(documentation.links."RFC9562-V4")
+ \(documentation.links."CBOR-TAG-37")
"""
comment: "UUIDv4"
}
- "document_type": {
+ document_type: {
def: "[ 1* \(requires[0]) ]"
requires: ["uuid_v4"]
description: "Unique Document Type Identifier"
comment: "Document Type"
}
- "blake2b_256": {
+ blake2b_256: {
def: "bytes .size 32"
description: "Blake2b Hash (256 bits)"
comment: "Blake2B-256"
}
- "document_id": {
+ document_id: {
def: "\(requires[0])"
requires: ["uuid_v7"]
description: "Unique Document Identifier"
comment: "Document ID"
}
- "document_ver": {
+ document_ver: {
def: "\(requires[0])"
requires: ["uuid_v7"]
description: "Unique Chronological Document Version Identifier"
comment: "Document Version"
}
- "cid": {
+ cid: {
def: "#6.42(bytes)"
description: """
IPLD content identifier.
Also known as an IPFS CID
- See: \(documentationLinks."IPFS-CID")
- \(documentationLinks."CBOR-TAG-42")
+ See: \(documentation.links."IPFS-CID")
+ \(documentation.links."CBOR-TAG-42")
"""
comment: """
IPLD content identifier
TODO: add size limits if possible
"""
}
- "document_locator": {
+ document_locator: {
def: """
{
\"cid\" => \(requires[0])
@@ -77,41 +77,48 @@ cddlDefinitions: #cddlDefinitions & {
requires: ["cid"]
comment: "Where a document can be located, must be a unique identifier."
}
- "document_ref": {
+ document_refs: {
+ def: "[ 1* \(requires[0]) ]"
+ requires: [
+ "document_ref",
+ ]
+ comment: "Reference to one or more Signed Documents"
+ }
+ document_ref: {
def: """
- [ 1* [
+ [
\(requires[0]),
\(requires[1]),
\(requires[2])
- ] ]
+ ]
"""
requires: [
"document_id",
"document_ver",
"document_locator",
]
- comment: "Reference to another Signed Document"
+ comment: "Reference to a single Signed Document"
}
- "json_pointer": {
+ json_pointer: {
def: "text"
comment: "RFC6901 Standard JSON Pointer"
}
- "section_ref": {
+ section_ref: {
def: "\(requires[0])"
requires: ["json_pointer"]
comment: "Reference to a section in a referenced document."
}
- "collaborators": {
+ collaborators: {
def: "[ * \(requires[0]) ]"
requires: ["catalyst_id_kid"]
comment: "Allowed Collaborators on the next subsequent version of a document."
}
- "revocations": {
+ revocations: {
def: "[ * \(requires[0]) ] / true "
requires: ["document_ver"]
comment: "List of revoked versions of this document."
}
- "media_type": {
+ media_type: {
def: """
(
(uint .eq (\(_cddlCoapTypes))) /
@@ -122,23 +129,58 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: """
Supported Content Media Types.
- If uint is used, only CoAP Content Formats that match the string format are allowed.
+ If the Media Type is supported by COAP, then the `uint` CoAP encoded
+ version of the media type must be used, in preference to the string.
"""
}
- "http_content_encoding": {
+ http_content_encoding: {
def: """
tstr .eq "br"
"""
comment: "Supported Content Encoding Types"
}
- "catalyst_id_kid": {
+ catalyst_id_kid: {
def: "bytes"
comment: "UTF8 Catalyst ID URI encoded as a bytes string."
}
- "revocations": {
+ revocations: {
def: "[ * document_ver ] / true "
requires: ["document_ver"]
}
+ chain: {
+ def: "[\(requires[0]), ? \(requires[1])]"
+ requires: [
+ "height",
+ "document_ref",
+ ]
+ comment: """
+ Reference to the previous Signed Document in a sequence.
+ * `\(requires[0])` is of the CURRENT block.
+ * `\(requires[1])` is *ONLY* omitted in the very first document in a sequence.
+ """
+ }
+ height: {
+ def: "int"
+ comment: """
+ The consecutive sequence number of the current document
+ in the chain.
+ The very first document in a sequence is numbered `0` and it
+ *MUST ONLY* increment by one for each successive document in
+ the sequence.
+
+ The FINAL sequence number is encoded with the current height
+ sequence value, negated.
+
+ For example the following values for height define a chain
+ that has 5 documents in the sequence 0-4, the final height
+ is negated to indicate the end of the chain:
+ `0, 1, 2, 3, -4`
+
+ No subsequent document can be chained to a sequence that has
+ a final chain height.
+ """
+ }
+
}
#cddlTypes: [
diff --git a/specs/definitions/signed_docs/cose_headers.cue b/specs/definitions/signed_docs/cose_headers.cue
new file mode 100644
index 0000000000..0027b77fb2
--- /dev/null
+++ b/specs/definitions/signed_docs/cose_headers.cue
@@ -0,0 +1,117 @@
+// Signed Document Definitions
+//
+// COSE Headers and Constraints
+package signed_docs
+
+import (
+ "list"
+ "github.com/input-output-hk/catalyst-libs/specs/generic:optional"
+ "github.com/input-output-hk/catalyst-libs/specs/media_types"
+)
+
+// Canonical List of COSE header names
+_coseHeaderNames: list.UniqueItems
+_coseHeaderNames: [
+ "alg",
+ "crit",
+ "content type",
+ "content-encoding", // Not strictly a true Cose Header, but we include it because of its relationship to `content type`
+ "kid",
+ "IV",
+ "Partial IV",
+ "counter signature",
+]
+
+_allCoseHeaderNames: or([
+ for k in _coseHeaderNames {k},
+])
+
+cose: headerFormats: #metadataFormats & {
+ "Media Type": {
+ description: "A Media Type string which identifies the payload."
+ cddl: "media_type"
+ }
+ "HTTP Content Encoding": {
+ description: "Encoding if any on the payload."
+ cddl: "http_content_encoding"
+ }
+ "Catalyst ID": {
+ description: "KID (Catalyst ID URI)"
+ cddl: "catalyst_id_kid"
+ }
+}
+
+// Types of a Metadata Fields
+#coseHeaderTypes: [
+ for k, _ in cose.headerFormats {k},
+]
+
+// Constraint of Types of Cose Header Fields
+#coseHeaderTypesConstraint: or(#coseHeaderTypes)
+
+#coseField: {
+ coseLabel: int | string
+ description: string
+ required: optional.#field | *"yes"
+ format: #coseHeaderTypesConstraint
+ if format == "Media Type" {
+ value: media_types.#contentType | [...media_types.#contentType]
+ }
+
+ if format == "HTTP Content Encoding" {
+ value: media_types.allContentEncoding
+ }
+}
+
+// Metadata Fields that are required for every signed document
+#coseHeaders: {
+ [_allCoseHeaderNames]: #coseField
+}
+_coseHeaders: #coseHeaders & {
+ // Documents content type
+ "content type": #coseField & {
+ coseLabel: 3
+ format: "Media Type"
+ description: "Media Type/s allowed in the Payload"
+ }
+ // Documents Used content encodings
+ "content-encoding": #coseField & {
+ coseLabel: "content-encoding"
+ format: "HTTP Content Encoding"
+ required: "optional"
+ description: """
+ Supported HTTP Encodings of the Payload.
+ If no compression or encoding is used, then this field must not be present.
+ """
+ }
+}
+
+_coseSignatureHeaders: #coseHeaders & {
+ // Key identifier
+ kid: #coseField & {
+ coseLabel: 4
+ format: "Catalyst ID"
+ description: """
+ Catalyst ID URI identifying the Public Key.
+
+ The `kid` is a UTF-8 encoded Catalyst ID URI.
+ Any `kid` URI which conforms to the Catalyst ID specification may be used.
+ The Catalyst ID unambiguously defines both the signing keys and signing algorithm
+ used to sign the protected portion of the document.
+ """
+ }
+}
+
+cose: headers: _coseHeaders
+cose: headers: "content type": value: media_types.allContentTypes
+
+// Preferred display order of cose header fields.
+// if header not listed, display after the listed fields, in alphabetical order.
+cose: headersOrder: list.UniqueItems
+cose: headersOrder: [
+ "content type",
+ "content-encoding",
+]
+
+// Headers defined for signatures.
+cose: signature_headers: _coseSignatureHeaders
diff --git a/specs/signed_docs/cose_signed_doc_cddl_defs.cue b/specs/definitions/signed_docs/cose_signed_doc_cddl_defs.cue
similarity index 84%
rename from specs/signed_docs/cose_signed_doc_cddl_defs.cue
rename to specs/definitions/signed_docs/cose_signed_doc_cddl_defs.cue
index ef9091d1d5..94d78fec06 100644
--- a/specs/signed_docs/cose_signed_doc_cddl_defs.cue
+++ b/specs/definitions/signed_docs/cose_signed_doc_cddl_defs.cue
@@ -5,16 +5,17 @@ package signed_docs
import (
"strings"
+ "github.com/input-output-hk/catalyst-libs/specs/media_types"
)
// Formatted content strings to use in CDDL Definition.
-_cddlContentTypes: "\"\(strings.Join(cose_headers."content type".value, "\" /\n \""))\""
+_cddlContentTypes: "\"\(strings.Join(cose.headers."content type".value, "\" /\n \""))\""
// Formatted CoAP content string to use in CDDL Definition.
-_cddlCoapTypes: "\(strings.Join(_allCoapTypesStr, " / "))"
+_cddlCoapTypes: "\(strings.Join(media_types.allCoapTypesStr, " / "))"
cddlDefinitions: #cddlDefinitions & {
- "signed_document": {
+ signed_document: {
requires: ["COSE_Sign"]
def: "\(requires[0])"
description: """
@@ -24,13 +25,13 @@ cddlDefinitions: #cddlDefinitions & {
used by the Catalyst project to encapsulate and authenticate
documents used within the system.
- See: \(documentationLinks."RFC9052-CoseSign")
+ See: \(documentation.links."RFC9052-CoseSign")
"""
comment: """
Catalyst Signed Document data object.
"""
}
- "COSE_Sign": {
+ COSE_Sign: {
requires: [
"COSE_Document_Headers",
"COSE_Signature",
@@ -44,7 +45,7 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: "COSE-SIGN data object"
}
- "COSE_Document_Headers": {
+ COSE_Document_Headers: {
requires: [
"COSE_Document_Header_Map",
"COSE_Generic_Headers",
@@ -57,7 +58,7 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: "COSE Document headers (only protected headers are used)"
}
- "COSE_Document_Header_Map": {
+ COSE_Document_Header_Map: {
requires: [
"COSE_Document_Standard_Headers",
"Signed_Document_Metadata_Headers",
@@ -72,7 +73,7 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: "COSE Document Header Map"
}
- "COSE_Document_Standard_Headers": {
+ COSE_Document_Standard_Headers: {
def: """
(
? 1 => int / tstr, ; algorithm identifier
@@ -88,14 +89,14 @@ cddlDefinitions: #cddlDefinitions & {
"COSE_label",
]
}
- "Signed_Document_Metadata_Headers": {
+ Signed_Document_Metadata_Headers: {
def: "\(requires[0])"
comment: "Generic definition (does not include metadata constraints)"
requires: [
"COSE_Generic_Headers",
]
}
- "COSE_Signature_Headers": {
+ COSE_Signature_Headers: {
requires: [
"COSE_Signature_Header_Map",
"COSE_Generic_Headers",
@@ -108,7 +109,7 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: "COSE Signature headers (only protected headers are used)"
}
- "COSE_Signature": {
+ COSE_Signature: {
def: """
[
\(requires[0]),
@@ -118,7 +119,7 @@ cddlDefinitions: #cddlDefinitions & {
requires: ["COSE_Signature_Headers"]
comment: "An Individual Document Signature"
}
- "COSE_Signature_Header_Map": {
+ COSE_Signature_Header_Map: {
requires: [
"COSE_Signature_Standard_Headers",
"COSE_Generic_Headers",
@@ -131,7 +132,7 @@ cddlDefinitions: #cddlDefinitions & {
"""
comment: "COSE Signature Header Map"
}
- "COSE_Signature_Standard_Headers": {
+ COSE_Signature_Standard_Headers: {
def: """
(
? 1 => int / tstr, ; algorithm identifier
@@ -150,7 +151,7 @@ cddlDefinitions: #cddlDefinitions & {
"COSE_Generic_Headers",
]
}
- "COSE_Generic_Headers": {
+ COSE_Generic_Headers: {
def: "( * \(requires[0]) => \(requires[1]) )"
comment: "Generic Header definition"
requires: [
@@ -158,11 +159,11 @@ cddlDefinitions: #cddlDefinitions & {
"COSE_values",
]
}
- "COSE_label": {
+ COSE_label: {
def: "int / tstr"
comment: "COSE Map Generic Label"
}
- "COSE_values": {
+ COSE_values: {
def: "any"
comment: "COSE Map Generic Value"
}
diff --git a/specs/definitions/signed_docs/docs/all.cue b/specs/definitions/signed_docs/docs/all.cue
new file mode 100644
index 0000000000..71c8645fae
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/all.cue
@@ -0,0 +1,158 @@
+// Master list of all document types.
+package signed_docs
+
+import (
+ "list"
+)
+
+// Named Type UUIDs for easier definitions/references
+_allDocTypes: {
+ FormTemplate: "0ce8ab38-9258-4fbc-a62e-7faa6e58318f"
+ PresentationTemplate: "cb99b9bd-681a-49d8-9836-89107c02e8ef"
+ Proposal: "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ Comment: "b679ded3-0e7c-41ba-89f8-da62a17898ea"
+ Action: "5e60e623-ad02-4a1b-a1ac-406db978ee48"
+ SubmissionAction: "78927329-cfd9-4ea1-9c71-0e019b126a65"
+ ModerationAction: "a5d232b8-5e03-4117-9afd-be32b878fcdd"
+ Brand: "ebcabeeb-5bc5-4f95-91e8-cab8ca724172"
+ Campaign: "5ef32d5d-f240-462c-a7a4-ba4af221fa23"
+ Category: "818938c3-3139-4daa-afe6-974c78488e95"
+ Contest: "788ff4c6-d65a-451f-bb33-575fe056b411"
+ Parameters: "60185874-7e13-407c-a06c-238ffe637ae6"
+ RegisteredUser: "ff4b7724-3db5-44cd-a433-78ba6d29505e"
+ RegisteredRep: "94579df1-a6dc-433b-a8e8-910c5dc2f0e3"
+ RegisteredProposer: "7311c63b-95c6-402e-a258-f9bf622093eb"
+ Profile: "0f2c86a2-ffda-40b0-ad38-23709e1c10b3"
+ Nomination: "bf9abd97-5d1f-4429-8e80-740fea371a9c"
+ Delegation: "764f17fb-cc50-4979-b14a-b213dbac5994"
+}
+
+// Source of truth for ALL Document Types and their matching UUID's.
+// Format is : :
+_allDocs: {
+ "Proposal Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Proposal"], // For Proposals
+ ]
+ "Proposal Presentation Template": [
+ _allDocTypes["PresentationTemplate"], // Presentation Template
+ _allDocTypes["Proposal"], // For Proposals
+ ]
+ Proposal: [
+ _allDocTypes["Proposal"],
+ ]
+ "Proposal Comment Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Comment"], // For Comments
+ _allDocTypes["Proposal"], // On Proposals
+ ]
+ "Proposal Comment Presentation Template": [
+ _allDocTypes["PresentationTemplate"], // PresentationTemplate
+ _allDocTypes["Comment"], // For Comments
+ _allDocTypes["Proposal"], // On Proposals
+ ]
+ "Proposal Comment": [
+ _allDocTypes["Comment"], // Comment
+ _allDocTypes["Proposal"], // For Proposals
+ ]
+ "Proposal Submission Action":
+ [
+ _allDocTypes["Action"], // Action
+ _allDocTypes["Proposal"], // For Proposal
+ _allDocTypes["SubmissionAction"], // On Submission
+ ]
+ "Proposal Moderation Action":
+ [
+ _allDocTypes["Action"], // Action
+ _allDocTypes["Proposal"], // For Proposal
+ _allDocTypes["ModerationAction"], // On Moderation
+ ]
+ "Comment Moderation Action": [
+ _allDocTypes["Action"], // Action
+ _allDocTypes["Comment"], // For Comment
+ _allDocTypes["ModerationAction"], // On Moderation
+ ]
+ "Brand Parameters": [
+ _allDocTypes["Parameters"], // Parameters
+ _allDocTypes["Brand"], // Of a Brand
+ ]
+ "Brand Parameters Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Parameters"], // For Parameters
+ _allDocTypes["Brand"], // Of a Brand
+ ]
+ "Campaign Parameters": [
+ _allDocTypes["Parameters"], // Parameters
+ _allDocTypes["Campaign"], // Of a Campaign
+ ]
+ "Campaign Parameters Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Parameters"], // For Parameters
+ _allDocTypes["Campaign"], // Of a Campaign
+ ]
+ "Category Parameters": [
+ _allDocTypes["Parameters"], // Parameters
+ _allDocTypes["Category"], // Of a Category
+ ]
+ "Category Parameters Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Parameters"], // For Parameters
+ _allDocTypes["Category"], // Of a Category
+ ]
+ "Contest Parameters": [
+ _allDocTypes["Parameters"], // Parameters
+ _allDocTypes["Contest"], // Of a Contest
+ ]
+ "Contest Parameters Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Parameters"], // For Parameters
+ _allDocTypes["Contest"], // Of a Contest
+ ]
+ "Rep Profile": [
+ _allDocTypes["Profile"], // Profile
+ _allDocTypes["RegisteredRep"], // Of a Registered Rep
+ ]
+ "Rep Profile Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Profile"], // For a Profile
+ _allDocTypes["RegisteredRep"], // Of a Registered Rep
+ ]
+ "Rep Nomination": [
+ _allDocTypes["Nomination"], // Nomination
+ _allDocTypes["RegisteredRep"], // Of a Registered Rep
+ ]
+ "Rep Nomination Form Template": [
+ _allDocTypes["FormTemplate"], // Form Template
+ _allDocTypes["Nomination"], // For a Nomination
+ _allDocTypes["RegisteredRep"], // Of a Registered Rep
+ ]
+ "Contest Delegation": [
+ _allDocTypes["Delegation"], // A Delegation
+ _allDocTypes["Contest"], // For a Contest
+ ]
+}
+
+// Document Cluster Definition
+#DocumentCluster: {
+ docs: [..._allDocNames]
+}
+
+#DocClusters: [string]: #DocumentCluster
+
+doc_clusters: #DocClusters & {
+ // System parameters define the system, excludes Contests.
+ "System Parameters": {
+ docs: [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters",
+ ]
+ }
+}
+
+// A Doc can only be in 1 cluster.
+#allDocClusterDocs: list.UniqueItems
+#allDocClusterDocs: [...string] & [
+ for cluster in doc_clusters
+ for doc in cluster.docs {doc},
+]
diff --git a/specs/signed_docs/docs/comment_moderation_action.cue b/specs/definitions/signed_docs/docs/comment_moderation_action.cue
similarity index 73%
rename from specs/signed_docs/docs/comment_moderation_action.cue
rename to specs/definitions/signed_docs/docs/comment_moderation_action.cue
index e30bdc90cf..0633e75d2e 100644
--- a/specs/signed_docs/docs/comment_moderation_action.cue
+++ b/specs/definitions/signed_docs/docs/comment_moderation_action.cue
@@ -7,13 +7,11 @@ docs: #DocumentDefinitions & {
description: """
A Moderation Action performed on any Comment.
"""
+ headers: "content type": value: "application/json"
- metadata: {
- ref: {
- required: "yes"
- type: ["Proposal Comment"]
- }
-
+ metadata: ref: {
+ required: "yes"
+ type: ["Proposal Comment"]
}
versions: [
diff --git a/specs/definitions/signed_docs/docs/contest_delegation.cue b/specs/definitions/signed_docs/docs/contest_delegation.cue
new file mode 100644
index 0000000000..4352620a6e
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/contest_delegation.cue
@@ -0,0 +1,82 @@
+@extern(embed)
+
+package signed_docs
+
+docs: "Contest Delegation": {
+ description: """
+ Delegation by a Registered User to a Representative for
+ a contest.
+
+ This delegation allows votes cast by the Representative
+ to use the voting power of the delegating User, in addition
+ to their own personal voting power and that of all other Users
+ who delegate to the same Representative.
+
+ Delegation is for a specific Contest.
+ Multiple Delegations must be published if there are multiple
+ Contests within a Brand/Campaign or Category.
+
+ This is because different Contests may have different rules.
+ And not all Representatives will choose to nominate
+ for every Contest.
+ """
+ validation: """
+ * The `parameters` metadata *MUST* point to the same Contest as the
+ Nomination of the Representative.
+ * The 'ref' metadata field MUST point to a valid 'Representative Nomination'.
+ * The payload MUST be nil.
+
+ A Representative *MUST* Delegate to their latest Nomination for a Category,
+ otherwise their Nomination is invalid.
+
+ \(docs."Rep Nomination"._latest_nomination_note)
+ """
+ business_logic: {
+ front_end: """
+ * Allows a voter to select a Representative from a list of eligible candidates for a category.
+ * The voter signs this document to confirm their delegation choice.
+ """
+ back_end: """
+ * Verifies that the voter and Representative are valid and registered for the category.
+ * Records the delegation of voting power from the voter to the Representative.
+ """
+ }
+
+ //headers: "content type": value: "application/cbor"
+ metadata: {
+ ref: {
+ required: "yes"
+ type: "Rep Nomination"
+ }
+ parameters: {
+ required: "yes"
+ type: "Contest Parameters"
+ linked_refs: [
+ "ref",
+ ]
+ }
+ }
+ payload: {
+ description: """
+ A minimal payload indicating the intended status of the delegation.
+ 'active' creates or affirms the delegation.
+ 'revoked' withdraws the delegation.
+ """
+
+ nil: true
+ }
+
+ signers: roles: user: [
+ "Registered",
+ ]
+ authors: "Neil McAuliffe": "neil.mcauliffe@iohk.io"
+ versions: [
+ {
+ version: "0.01"
+ modified: "2025-06-19"
+ changes: """
+ * First Published Version
+ """
+ },
+ ]
+}
diff --git a/specs/definitions/signed_docs/docs/generic_form_template.cue b/specs/definitions/signed_docs/docs/generic_form_template.cue
new file mode 100644
index 0000000000..555d18fd3d
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/generic_form_template.cue
@@ -0,0 +1,97 @@
+// Template Standardized Descriptions
+package signed_docs
+
+_form_template_description: """
+ A {{ .doc }} Form Template defines both:
+
+ * The data that is entered in the Form.
+ * Formatting hints for the collection of the data in a form.
+
+ A {{ .doc }} Form Template is a JSON Schema Document.
+
+ {{ .doc }} entry *SHOULD* use the hints when collecting
+ data defined by the {{ .doc }} Form Template to provide a
+ consistent user interface.
+ It *CAN* also use those hints when re-displaying the full forms data.
+
+ Alternatively a {{ .doc }} Presentation Template can be used to
+ format the {{ .doc }} data for presentation.
+
+ The {{ .doc }} Document is intentionally general,
+ however it may be linked to a brand/campaign or category
+ via the template used by the {{ .doc }}.
+
+ The payload of a {{ .doc }} is controlled by its template.
+ """
+
+_form_template_payload_description: """
+ JSON Schema document which defines the valid contents and
+ formatting hints for the collection of data for a
+ {{ .doc }} Document.
+ """
+
+// Used for documents that can link to any system parameter.
+_metadataFieldSystemParameters: #metadataField & {
+ // Is the field required to be present.
+ required: "yes"
+ type: doc_clusters."System Parameters".docs
+}
+
+// Used for documents that can only link to brand parameters.
+_metadataFieldBrandParameters: #metadataField & {
+ // Is the field required to be present.
+ required: "yes"
+ type: ["Brand Parameters"]
+}
+
+// Used for documents that can only link to contest parameters.
+_metadataFieldContestParameters: #metadataField & {
+ // Is the field required to be present.
+ required: "yes"
+ type: "Contest Parameters"
+}
+
+#generic_form_template: #signedDocument & {
+ description: _
+
+ headers: "content type": value: "application/schema+json"
+
+ metadata: template: required: "excluded"
+
+ payload: description: _
+
+ signers: roles: {
+ // No User Role may publish this document.
+ user: []
+
+ // Brand Admin and Lower may publish this document.
+ admin: _ | *[
+ "Brand Admin",
+ ]
+ }
+
+}
+
+_generic_form_template_versions: [#changelogEntry, ...#changelogEntry] & [
+ {
+ version: "0.01"
+ modified: "2025-04-04"
+ changes: """
+ * First Published Version
+ """
+ },
+ {
+ version: "0.03"
+ modified: "2025-05-05"
+ changes: """
+ * Use generalized parameters.
+ """
+ },
+ {
+ version: "0.04"
+ modified: "2025-05-05"
+ changes: """
+ * Generalize the Form Template definitions.
+ """
+ },
+]
diff --git a/specs/definitions/signed_docs/docs/generic_parameters.cue b/specs/definitions/signed_docs/docs/generic_parameters.cue
new file mode 100644
index 0000000000..361241f7a9
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/generic_parameters.cue
@@ -0,0 +1,88 @@
+// Parameters Standardized Document Definition
+package signed_docs
+
+_parameters_description: """
+ {{ .doc }} Parameters define the parameter data required for the
+ system at the {{ .doc }} level.
+
+ Parameter Data includes things such as:
+
+ * Functional parameters
+ * Timeline data
+ * Branded Content and Copy
+
+ The content of the parameters is defined solely by the
+ {{ .doc }} Parameters Form Template.
+
+ This allows parameters to vary based on individual system
+ requirements over time.
+
+ Functional Parameters are mapped using the (TBD Functional Parameters Map).
+
+ The payload of a {{ .doc }} is controlled by its template.
+ """
+
+_parameters_parent_validation: """
+ The {{ .doc }} Parameters Document *MUST* be linked through `parameters` to
+ its {{ .doc_parent }} Parameters Document.
+ """
+
+_parameters_payload_description: """
+ {{ .doc }} Parameters Document controlling the {{ .doc }}
+ within a {{ .doc_parent }}.
+
+ Must be valid according to the schema contained within the
+ `Document Reference` from the `template` metadata.
+ """
+
+#generic_parameters: #signedDocument & {
+
+ description: _
+
+ metadata: {
+ template: required: "yes"
+
+ collaborators: required: "optional"
+
+ revocations: required: "optional"
+
+ parameters: required: _ | *"yes"
+ }
+
+ headers: "content type": value: "application/json"
+
+ payload: description: _
+
+ signers: {
+ roles: {
+ user: []
+ admin: [
+ "Brand Admin",
+ ]
+ }
+ update: collaborators: true
+ }
+
+ authors: {
+ "Steven Johnson": "steven.johnson@iohk.io"
+ "Nathan Bogale": "nathan.bogale@iohk.io"
+ }
+
+}
+
+_generic_parameters_versions: [
+ {
+ version: "0.01"
+ modified: "2025-04-04"
+ changes: """
+ * First Published Version
+ """
+ },
+ {
+ version: "0.02"
+ modified: "2025-06-20"
+ changes: """
+ * Generalized as another kind of form data document
+ """
+ },
+]
diff --git a/specs/definitions/signed_docs/docs/generic_presentation_template.cue b/specs/definitions/signed_docs/docs/generic_presentation_template.cue
new file mode 100644
index 0000000000..dfd8a3d5bf
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/generic_presentation_template.cue
@@ -0,0 +1,66 @@
+package signed_docs
+
+// Template Standardized Descriptions
+
+_presentation_template_description: """
+ A {{ .doc }} Presentation Template defines how the data
+ captured by the {{ .doc }} Form Template is to be displayed.
+
+ Multiple {{ .doc }} Presentation Templates can exist for the
+ same {{.doc }} Form Template.
+ Each can be used to display the form data under different
+ circumstances.
+
+ {{ .doc }} Presentation Templates can reference any data contained
+ in the {{ .doc }} Document, as well as any documents linked by:
+
+ * `ref`
+ * `reply`
+ * `parameters`
+
+ The presentation of the payload of a {{ .doc }} is controlled by
+ its {{ .doc }} Presentation Template/s.
+ """
+
+_presentation_template_payload_description: """
+ TBD.
+ But roughly, will be:
+
+ 1. A way to identify where the presentation template is intended to be used.
+ 2. Optional CSS to control the presentation.
+ 3. A Handlebars templated HTML or Markdown file data which defines the presentation.
+ """
+
+#generic_presentation_template: #signedDocument & {
+ description: _
+
+ headers: "content type": value: "application/schema+json"
+
+ metadata: parameters: {
+ required: "yes"
+ type: doc_clusters."System Parameters".docs
+ }
+
+ payload: description: _
+
+ signers: roles: {
+ // No User Role may publish this document.
+ user: []
+
+ // Brand Admin and Lower may publish this document.
+ admin: [
+ "Brand Admin",
+ "Campaign Admin",
+ ]
+ }
+}
+
+_generic_presentation_template_versions: [#changelogEntry, ...#changelogEntry] & [
+ {
+ version: "0.04"
+ modified: "2025-05-05"
+ changes: """
+ * First Version.
+ """
+ },
+]
diff --git a/specs/definitions/signed_docs/docs/parameters_brand.cue b/specs/definitions/signed_docs/docs/parameters_brand.cue
new file mode 100644
index 0000000000..9912db59e8
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_brand.cue
@@ -0,0 +1,21 @@
+// Brand Parameters Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Brand Parameters": #generic_parameters & {
+
+ _data: {
+ doc: "Brand"
+ doc_parent: "Brand"
+ }
+
+ description: template.Execute(_parameters_description, _data)
+ validation: "No extra validation defined."
+ metadata: {
+ template: type: "\(_data.doc) Parameters Form Template"
+ parameters: required: "excluded"
+ }
+ payload: description: template.Execute(_parameters_payload_description, _data)
+ versions: _generic_parameters_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_brand_form_template.cue b/specs/definitions/signed_docs/docs/parameters_brand_form_template.cue
new file mode 100644
index 0000000000..d0ebca07e3
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_brand_form_template.cue
@@ -0,0 +1,11 @@
+// Proposal Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Brand Parameters Form Template": #generic_form_template & {
+ _data: doc: "Brand Parameters"
+ description: template.Execute(_form_template_description, _data)
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_campaign.cue b/specs/definitions/signed_docs/docs/parameters_campaign.cue
new file mode 100644
index 0000000000..f6746e18d6
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_campaign.cue
@@ -0,0 +1,24 @@
+// Brand Parameters Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Campaign Parameters": #generic_parameters & {
+
+ _data: {
+ doc: "Campaign"
+ doc_parent: "Brand"
+ }
+
+ description: template.Execute(_parameters_description, _data)
+ validation: template.Execute(_parameters_parent_validation, _data)
+ metadata: {
+ template: type: "\(_data.doc) Parameters Form Template"
+ parameters: {
+ required: "yes"
+ type: "\(_data.doc_parent) Parameters"
+ }
+ }
+ payload: description: template.Execute(_parameters_payload_description, _data)
+ versions: _generic_parameters_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_campaign_form_template.cue b/specs/definitions/signed_docs/docs/parameters_campaign_form_template.cue
new file mode 100644
index 0000000000..0fd85abd1e
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_campaign_form_template.cue
@@ -0,0 +1,12 @@
+// Campaign Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Campaign Parameters Form Template": #generic_form_template & {
+ _data: doc: "Campaign Parameters"
+
+ description: template.Execute(_form_template_description, _data)
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_category.cue b/specs/definitions/signed_docs/docs/parameters_category.cue
new file mode 100644
index 0000000000..97a94003e1
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_category.cue
@@ -0,0 +1,24 @@
+// Category Parameters Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Category Parameters": #generic_parameters & {
+
+ _data: {
+ doc: "Category"
+ doc_parent: "Campaign"
+ }
+
+ description: template.Execute(_parameters_description, _data)
+ validation: template.Execute(_parameters_parent_validation, _data)
+ metadata: {
+ template: type: "\(_data.doc) Parameters Form Template"
+ parameters: {
+ required: "yes"
+ type: "\(_data.doc_parent) Parameters"
+ }
+ }
+ payload: description: template.Execute(_parameters_payload_description, _data)
+ versions: _generic_parameters_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_category_form_template.cue b/specs/definitions/signed_docs/docs/parameters_category_form_template.cue
new file mode 100644
index 0000000000..01191d5209
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_category_form_template.cue
@@ -0,0 +1,12 @@
+// Category Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Category Parameters Form Template": #generic_form_template & {
+ _data: doc: "Category Parameters"
+
+ description: template.Execute(_form_template_description, _data)
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_contest.cue b/specs/definitions/signed_docs/docs/parameters_contest.cue
new file mode 100644
index 0000000000..d464bf91b3
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_contest.cue
@@ -0,0 +1,21 @@
+// Contest Parameters Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Contest Parameters": #generic_parameters & {
+
+ _data: {
+ doc: "Contest"
+ doc_parent: "Brand/Campaign/Category"
+ }
+
+ description: template.Execute(_parameters_description, _data)
+ validation: template.Execute(_parameters_parent_validation, _data)
+ metadata: {
+ template: type: "\(_data.doc) Parameters Form Template"
+ parameters: _metadataFieldSystemParameters
+ }
+ payload: description: template.Execute(_parameters_payload_description, _data)
+ versions: _generic_parameters_versions
+}
diff --git a/specs/definitions/signed_docs/docs/parameters_contest_form_template.cue b/specs/definitions/signed_docs/docs/parameters_contest_form_template.cue
new file mode 100644
index 0000000000..9b3e0bef0f
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/parameters_contest_form_template.cue
@@ -0,0 +1,12 @@
+// Contest Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Contest Parameters Form Template": #generic_form_template & {
+ _data: doc: "Contest Parameters"
+
+ description: template.Execute(_form_template_description, _data)
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json
new file mode 100644
index 0000000000..747d3b6ec7
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json
@@ -0,0 +1,3 @@
+{
+ "action": "draft"
+}
\ No newline at end of file
diff --git a/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json
new file mode 100644
index 0000000000..bfbf15e59d
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json
@@ -0,0 +1,3 @@
+{
+ "action": "final"
+}
\ No newline at end of file
diff --git a/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json
new file mode 100644
index 0000000000..e6f023094f
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json
@@ -0,0 +1,3 @@
+{
+ "action": "hide"
+}
\ No newline at end of file
diff --git a/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json b/specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json
similarity index 100%
rename from specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json
rename to specs/definitions/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json
diff --git a/specs/signed_docs/docs/proposal.cue b/specs/definitions/signed_docs/docs/proposal.cue
similarity index 83%
rename from specs/signed_docs/docs/proposal.cue
rename to specs/definitions/signed_docs/docs/proposal.cue
index 776fe17cf6..bd7651cb27 100644
--- a/specs/signed_docs/docs/proposal.cue
+++ b/specs/definitions/signed_docs/docs/proposal.cue
@@ -3,7 +3,7 @@ package signed_docs
// Proposal Document Definition
docs: #DocumentDefinitions & {
- "Proposal": {
+ Proposal: {
description: """
A Proposal is a document which describes a proposed solution or project to
address the criteria of a category within a campaign.
@@ -54,20 +54,17 @@ docs: #DocumentDefinitions & {
* That the document has been signed validly according to the [validation](#validation) rules.
"""
}
+ headers: "content type": value: "application/json"
metadata: {
template: {
required: "yes"
- type: "Proposal Template"
+ type: "Proposal Form Template"
}
- collaborators: {
- required: "optional"
- }
+ collaborators: required: "optional"
- revocations: {
- required: "optional"
- }
+ revocations: required: "optional"
parameters: {
required: "yes"
@@ -78,30 +75,22 @@ docs: #DocumentDefinitions & {
}
}
- payload: {
- description: """
- Proposal Document drafted for submission to a category of a campaign.
+ payload: description: """
+ Proposal Document drafted for submission to a category of a campaign.
- Must be valid according to the schema contained within the
- `Document Reference` from the `template` metadata.
- """
- }
+ Must be valid according to the schema contained within the
+ `Document Reference` from the `template` metadata.
+ """
signers: {
- roles: {
- user: [
- "Proposer",
- ]
- }
+ roles: user: [
+ "Proposer",
+ ]
- update: {
- "collaborators": true
- }
+ update: collaborators: true
}
- authors: {
- "Steven Johnson": "steven.johnson@iohk.io"
- }
+ authors: "Steven Johnson": "steven.johnson@iohk.io"
versions: [
{
diff --git a/specs/signed_docs/docs/proposal_comment.cue b/specs/definitions/signed_docs/docs/proposal_comment.cue
similarity index 88%
rename from specs/signed_docs/docs/proposal_comment.cue
rename to specs/definitions/signed_docs/docs/proposal_comment.cue
index 95a2f30d2a..3df7f069b2 100644
--- a/specs/signed_docs/docs/proposal_comment.cue
+++ b/specs/definitions/signed_docs/docs/proposal_comment.cue
@@ -38,6 +38,9 @@ docs: #DocumentDefinitions & {
and the integrity of the `ref` and `reply` metadata fields is correct.
"""
}
+
+ headers: "content type": value: "application/json"
+
metadata: {
ref: {
required: "yes"
@@ -49,18 +52,14 @@ docs: #DocumentDefinitions & {
type: "Proposal Comment"
}
- section: {
- required: "optional"
- }
+ section: required: "optional"
template: {
required: "yes"
- type: "Proposal Comment Template"
+ type: "Proposal Comment Form Template"
}
- revocations: {
- required: "optional"
- }
+ revocations: required: "optional"
parameters: {
required: "yes"
@@ -72,11 +71,9 @@ docs: #DocumentDefinitions & {
}
}
- payload: {
- description: """
- JSON Document which must validate against the referenced template.
- """
- }
+ payload: description: """
+ JSON Document which must validate against the referenced template.
+ """
versions: [
{
diff --git a/specs/definitions/signed_docs/docs/proposal_comment_form_template.cue b/specs/definitions/signed_docs/docs/proposal_comment_form_template.cue
new file mode 100644
index 0000000000..111988d4e1
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/proposal_comment_form_template.cue
@@ -0,0 +1,13 @@
+// Proposal Comment Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Proposal Comment Form Template": #generic_form_template & {
+ _data: doc: "Proposal Comment"
+
+ description: template.Execute(_form_template_description, _data)
+ metadata: parameters: _metadataFieldSystemParameters
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/proposal_comment_presentation_template.cue b/specs/definitions/signed_docs/docs/proposal_comment_presentation_template.cue
new file mode 100644
index 0000000000..44ce2fe1c3
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/proposal_comment_presentation_template.cue
@@ -0,0 +1,12 @@
+// Proposal Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Proposal Comment Presentation Template": #generic_presentation_template & {
+ _data: doc: "Proposal Comment"
+
+ description: template.Execute(_presentation_template_description, _data)
+ payload: description: template.Execute(_presentation_template_payload_description, _data)
+ versions: _generic_presentation_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/proposal_form_template.cue b/specs/definitions/signed_docs/docs/proposal_form_template.cue
new file mode 100644
index 0000000000..10b22301a8
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/proposal_form_template.cue
@@ -0,0 +1,13 @@
+// Proposal Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Proposal Form Template": #generic_form_template & {
+ _data: doc: "Proposal"
+
+ description: template.Execute(_form_template_description, _data)
+ metadata: parameters: _metadataFieldSystemParameters
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/signed_docs/docs/proposal_moderation_action.cue b/specs/definitions/signed_docs/docs/proposal_moderation_action.cue
similarity index 73%
rename from specs/signed_docs/docs/proposal_moderation_action.cue
rename to specs/definitions/signed_docs/docs/proposal_moderation_action.cue
index e6fdcda9a8..63abeb5376 100644
--- a/specs/signed_docs/docs/proposal_moderation_action.cue
+++ b/specs/definitions/signed_docs/docs/proposal_moderation_action.cue
@@ -8,12 +8,12 @@ docs: #DocumentDefinitions & {
description: """
A Moderation action performed on a Proposal.
"""
+ headers: "content type": value: "application/json"
- metadata: {
- ref: {
- required: "yes"
- type: "Proposal"
- }}
+ metadata: ref: {
+ required: "yes"
+ type: "Proposal"
+ }
versions: [
{
diff --git a/specs/definitions/signed_docs/docs/proposal_presentation_template.cue b/specs/definitions/signed_docs/docs/proposal_presentation_template.cue
new file mode 100644
index 0000000000..dc40e50b01
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/proposal_presentation_template.cue
@@ -0,0 +1,12 @@
+// Proposal Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Proposal Presentation Template": #generic_presentation_template & {
+ _data: doc: "Proposal"
+
+ description: template.Execute(_presentation_template_description, _data)
+ payload: description: template.Execute(_presentation_template_payload_description, _data)
+ versions: _generic_presentation_template_versions
+}
diff --git a/specs/signed_docs/docs/proposal_submission_action.cue b/specs/definitions/signed_docs/docs/proposal_submission_action.cue
similarity index 75%
rename from specs/signed_docs/docs/proposal_submission_action.cue
rename to specs/definitions/signed_docs/docs/proposal_submission_action.cue
index 1db5557848..00c66f94a1 100644
--- a/specs/signed_docs/docs/proposal_submission_action.cue
+++ b/specs/definitions/signed_docs/docs/proposal_submission_action.cue
@@ -6,7 +6,7 @@ package signed_docs
docs: #DocumentDefinitions & {
"Proposal Submission Action": {
description: """
- ## Proposal Submission Action
+ Proposal Submission Action
A Proposal Submission Action is a document which can attempt to either submit a
particular version of a proposal into a campaign, or withdraw it.
@@ -62,6 +62,9 @@ docs: #DocumentDefinitions & {
is not considered `final` and will not be considered in the category it was being submitted to.
"""
}
+
+ headers: "content type": value: "application/json"
+
metadata: {
ref: {
type: "Proposal"
@@ -92,9 +95,35 @@ docs: #DocumentDefinitions & {
for a collaborator it identified that they do not wish to be listed as a `collaborator`.
"""
schema: _ @embed(file="payload_schemas/proposal_submission_action.schema.json")
+ examples: [
+ {
+ title: "Final Proposal Submission"
+ description: """
+ This document indicates the linked proposal is final and requested to proceed for further consideration.
+ """
+ example: _ @embed(file="payload_schemas/proposal_submission_action.final.example.json")
+ },
+ {
+ title: "Draft Proposal Submission"
+ description: """
+ This document indicates the linked proposal is no longer final and should not proceed for further consideration.
+ It is also used by collaborators to accept that they are a collaborator on a document.
+ """
+ example: _ @embed(file="payload_schemas/proposal_submission_action.draft.example.json")
+ },
+ {
+ title: "Hidden Proposal Submission"
+ description: """
+ If submitted by the proposal author the document is hidden, it is still public but not shown as
+ a proposal being drafted.
+ If submitted by a collaborator, that collaborator is declaring they do not wish to be listed as
+ a collaborator on the proposal.
+ """
+ example: _ @embed(file="payload_schemas/proposal_submission_action.hide.example.json")
+ },
+ ]
}
-
- "signers": {
+ signers: {
roles: {
// Proposers may publish this document.
user: [
@@ -104,9 +133,7 @@ docs: #DocumentDefinitions & {
referenced: true
- update: {
- collaborators: true
- }
+ update: collaborators: true
}
versions: [
diff --git a/specs/definitions/signed_docs/docs/rep_nomination_form_template.cue b/specs/definitions/signed_docs/docs/rep_nomination_form_template.cue
new file mode 100644
index 0000000000..b06c8f012e
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/rep_nomination_form_template.cue
@@ -0,0 +1,14 @@
+// Representative Profile Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Rep Nomination Form Template": #generic_form_template & {
+
+ _data: doc: "Rep Nomination"
+
+ description: template.Execute(_form_template_description, _data)
+ metadata: parameters: _metadataFieldContestParameters
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/docs/rep_nomintion.cue b/specs/definitions/signed_docs/docs/rep_nomintion.cue
new file mode 100644
index 0000000000..617016dbd8
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/rep_nomintion.cue
@@ -0,0 +1,128 @@
+package signed_docs
+
+// Proposal Document Definition
+
+docs: "Rep Nomination": {
+ _latest_nomination_note: """
+ This is because Delegation points to a *SPECIFIC* Nomination, and it
+ *MUST* be the latest for the Representative on the Contest.
+ As the Nomination contains information that the User relies on
+ when choosing to delegate, changing that information could have a
+ real and detrimental result in the Delegation choice.
+ Therefore, for a Delegation to be valid, it *MUST* point to the
+ latest Nomination for a Representative.
+ """
+
+ description: """
+ A Representative Nomination Document is created to opt
+ in as a Representative Voter for a specific Contest on a Brand/Campaign or Category.
+
+ This Document is a kind of `Profile` that is primarily used to
+ help justify the Representatives Nomination to prospective delegators.
+
+ The user must have registered as a Representative.
+ The presence of this document signifies the user's intent to participate in that
+ contest as a Representative.
+
+ The document's structure is defined by the associated
+ Rep Nomination Form Template.
+ This allows an Admin to specify contest-specific requirements.
+
+ The Representative can retract their nomination by using the `revoke` metadata to
+ revoke this Nomination document.
+
+ It is an extension of all other profiles attached to the same Catalyst ID.
+
+ Profiles themselves are intentionally general, however they may be
+ linked to a Brand/Campaign/Category via the template used by the profile.
+
+ The payload of a profile is controlled by its template.
+ """
+
+ validation: """
+ * The signer MUST be a registered 'Representative'.
+ * The 'ref' metadata field MUST point to a valid 'Representative Profile' document.
+ * The 'parameters' metadata field MUST point to a valid 'Contest Parameters' document.
+ * The 'template' metadata field MUST point to a valid 'Representative Nomination Form Template' document.
+ * The payload MUST be valid against the JSON schema defined in the referenced template.
+ * Other rules may apply as defined by the Contest or other parameters which can
+ control who may validly nominate as a representative in a Contest.
+
+ No Nomination is valid unless the latest Contest Delegation of the Delegate
+ refers to their own Nomination.
+ This requires that Nominating is a two step process:
+
+ 1. Post the Nomination Document.
+ 2. Post a Contest Delegation delegating to the new Nomination Document.
+
+ Updating the Nomination Document will invalidate all Nominations to the
+ Representative.
+
+ \(_latest_nomination_note)
+ """
+
+ business_logic: {
+
+ front_end: """
+ * Allows a Representative to create or update their profile for a category.
+ * The Representative sets their status to 'active' to be discoverable for delegation.
+ * The Representative `revokes` the Nomination to signal they are no longer
+ participating in the category.
+ * Nominations are not valid if the latest Delegation by the Representative does NOT
+ reference their latest Nomination.
+ """
+
+ back_end: """
+ * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.
+ * The system will only consider Representatives as having valid Nominations if:
+ * Their latest Nomination in a Contest is not Revoked.
+ * Their latest Delegation in a Contest references their latest Nomination.
+ """
+ }
+ headers: "content type": value: "application/json"
+
+ metadata: {
+ ref: {
+ required: "yes"
+ type: "Rep Profile"
+ }
+
+ template: {
+ required: "yes"
+ type: "Rep Nomination Form Template"
+ }
+
+ revocations: required: "optional"
+
+ parameters: _metadataFieldContestParameters
+ parameters: linked_refs: [
+ "template",
+ ]
+ }
+
+ payload: description: """
+ The Representative's profile data for a specific contest.
+ Its structure is defined by the referenced template document.
+
+ In the case of Revoking a nomination the payload is `nil`.
+ """
+
+ signers: roles: user: [
+ "Representative",
+ ]
+
+ authors: {
+ "Neil McAuliffe": "neil.mcauliffe@iohk.io"
+ "Steven Johnson": "steven.johnson@iohk.io"
+ }
+
+ versions: [
+ {
+ version: "0.01"
+ modified: "2025-06-19"
+ changes: """
+ * First Published Version
+ """
+ },
+ ]
+}
diff --git a/specs/definitions/signed_docs/docs/rep_profile.cue b/specs/definitions/signed_docs/docs/rep_profile.cue
new file mode 100644
index 0000000000..77181b22d7
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/rep_profile.cue
@@ -0,0 +1,79 @@
+package signed_docs
+
+// Proposal Document Definition
+
+docs: "Rep Profile": {
+ description: """
+ A Rep Profile allows a representative voter to publish information
+ about themselves to help explain who they are and why someone should
+ consider delegating to them.
+
+ It is an extension of all other profiles attached to the same Catalyst ID.
+
+ Profiles themselves are intentionally general, however they may be
+ linked to a brand via the template used by the profile.
+
+ The payload of a profile is controlled by its template.
+ """
+
+ validation: """
+ * The signer MUST be a registered 'Representative'.
+ * The payload MUST be valid against the JSON schema defined in the referenced
+ 'Rep Profile Template'.
+ """
+
+ business_logic: {
+
+ front_end: """
+ * Display and allow editing of the Representative's core profile fields.
+ * This profile serves as the central hub for a Representative's public identity.
+ """
+
+ back_end: """
+ * Validate Representative profile data against the referenced 'Rep Profile Template' and store/index it.
+ * This global profile is the foundational document referenced by all of the Rep's contest specific profiles.
+ """
+ }
+ headers: "content type": value: "application/json"
+
+ metadata: {
+ template: {
+ required: "yes"
+ type: "Rep Profile Form Template"
+ }
+
+ revocations: required: "optional"
+
+ parameters: _metadataFieldBrandParameters
+ parameters: linked_refs: [
+ "template",
+ ]
+ }
+
+ payload: description: """
+ The Representative profile payload contains all Representative-specific fields.
+ Its structure is defined by the referenced Rep Profile Template.
+
+ Must be valid according to the schema contained within the
+ `Document Reference` from the `template` metadata.
+ """
+
+ signers: roles: user: [
+ "Representative",
+ ]
+
+ authors: {
+ "Neil McAuliffe": "neil.mcauliffe@iohk.io"
+ "Steven Johnson": "steven.johnson@iohk.io"
+ }
+
+ versions: [
+ {
+ version: "0.01"
+ modified: "2025-06-19"
+ changes: """
+ * First Published Version
+ """
+ },
+ ]
+}
diff --git a/specs/definitions/signed_docs/docs/rep_profile_form_template.cue b/specs/definitions/signed_docs/docs/rep_profile_form_template.cue
new file mode 100644
index 0000000000..82b7217114
--- /dev/null
+++ b/specs/definitions/signed_docs/docs/rep_profile_form_template.cue
@@ -0,0 +1,14 @@
+// Representative Profile Form Template Document Definition
+package signed_docs
+
+import "text/template"
+
+docs: "Rep Profile Form Template": #generic_form_template & {
+
+ _data: doc: "Rep Profile"
+
+ description: template.Execute(_form_template_description, _data)
+ metadata: parameters: _metadataFieldBrandParameters
+ payload: description: template.Execute(_form_template_payload_description, _data)
+ versions: _generic_form_template_versions
+}
diff --git a/specs/definitions/signed_docs/documentation.cue b/specs/definitions/signed_docs/documentation.cue
new file mode 100644
index 0000000000..c13f104122
--- /dev/null
+++ b/specs/definitions/signed_docs/documentation.cue
@@ -0,0 +1,16 @@
+// Links to external documentation
+
+package signed_docs
+
+import (
+ docs "github.com/input-output-hk/catalyst-libs/specs/documentation"
+ "github.com/input-output-hk/catalyst-libs/specs/media_types"
+)
+
+documentation: {
+ links: docs.links
+ linkAKA: docs.linkAKA
+}
+
+contentTypes: media_types.contentTypes
+encodingTypes: media_types.encodingTypes
diff --git a/specs/definitions/signed_docs/includes/fraudulent_chain.mermaid b/specs/definitions/signed_docs/includes/fraudulent_chain.mermaid
new file mode 100644
index 0000000000..5e87b72c64
--- /dev/null
+++ b/specs/definitions/signed_docs/includes/fraudulent_chain.mermaid
@@ -0,0 +1,54 @@
+classDiagram
+ direction LR
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#060,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#060,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#060,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
+ class Rejected {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(Other.Catalyst ID)
+ }
+
+ Rejected --|> Intermediate : Invalidly chains to
+ style Rejected fill:#100,stroke:#f00,stroke-width:4px
diff --git a/specs/definitions/signed_docs/includes/invalid_chain.mermaid b/specs/definitions/signed_docs/includes/invalid_chain.mermaid
new file mode 100644
index 0000000000..e9193cc674
--- /dev/null
+++ b/specs/definitions/signed_docs/includes/invalid_chain.mermaid
@@ -0,0 +1,70 @@
+classDiagram
+ direction LR
+
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#f60,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#f60,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#f60,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
+ class Invalid_Chain {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+
+ Invalid_Chain --|> First : Invalidly chains to
+ style Invalid_Chain fill:#100,stroke:#f00,stroke-width:4px
+
+
+ class After_Final {
+ type: "=Final.Document Type"
+ id: "=Final.Document ID"
+ ver: ">Final.Document ID"
+ parameters: "=Final.Document Parameters"
+ chain.height: 3
+ chain.document_ref: "=Last"
+
+ author(Last.Catalyst ID)
+ }
+
+ After_Final --|> Last : Invalidly chains to
+ style After_Final fill:#100,stroke:#f00,stroke-width:4px
diff --git a/specs/definitions/signed_docs/includes/valid_chain.mermaid b/specs/definitions/signed_docs/includes/valid_chain.mermaid
new file mode 100644
index 0000000000..4bfaff6b87
--- /dev/null
+++ b/specs/definitions/signed_docs/includes/valid_chain.mermaid
@@ -0,0 +1,41 @@
+classDiagram
+ direction LR
+ class Last {
+ type: "=Intermediate.Document Type"
+ id: "=Intermediate.Document ID"
+ ver: ">Intermediate.Document ID"
+ parameters: "=Intermediate.Document Parameters"
+ chain.height: -2
+ chain.document_ref: "=Intermediate"
+
+ author(Intermediate.Catalyst ID)
+ }
+ style Last stroke:#060,stroke-width:4px
+
+ class Intermediate {
+ type: "=First.Document Type"
+ id: "=First.Document ID"
+ ver: ">First.Document ID"
+ parameters: "=First.Document Parameters"
+ chain.height: 1
+ chain.document_ref: "=First"
+
+ author(First.Catalyst ID)
+ }
+ style Intermediate stroke:#060,stroke-width:4px
+
+ class First {
+ type: "Document Type"
+ id: "Document ID"
+ ver: "=Document ID"
+ parameters: "Document Parameters"
+ chain.height: 0
+ chain.document_ref: None
+
+ author(Catalyst ID)
+ }
+ style First stroke:#060,stroke-width:4px
+
+ Last --|> Intermediate : chains to
+ Intermediate --|> First : chains to
+
diff --git a/specs/signed_docs/metadata.cue b/specs/definitions/signed_docs/metadata.cue
similarity index 85%
rename from specs/signed_docs/metadata.cue
rename to specs/definitions/signed_docs/metadata.cue
index d814c80b06..cf70c2d443 100644
--- a/specs/signed_docs/metadata.cue
+++ b/specs/definitions/signed_docs/metadata.cue
@@ -1,12 +1,12 @@
// Signed Document Definitions
//
// Metadata Types and Constraints
+@extern(embed)
package signed_docs
import (
"list"
"github.com/input-output-hk/catalyst-libs/specs/generic:optional"
-
)
// Metadata Formats.
@@ -18,16 +18,17 @@ import (
}
}
-metadataFormats: #metadataFormats & {
+metadata: formats: #metadataFormats
+metadata: formats: {
"Document Reference": {
description: "A document reference identifier"
- cddl: "document_ref"
+ cddl: "document_refs"
}
- "UUIDv7": {
+ UUIDv7: {
description: "Version 7 formatted UUID"
cddl: "uuid_v7"
}
- "UUIDv4": {
+ UUIDv4: {
description: "Version 4 formatted UUID"
cddl: "uuid_v4"
}
@@ -43,6 +44,7 @@ metadataFormats: #metadataFormats & {
description: "A unique chronological document version"
cddl: "document_ver"
}
+
"Section Reference": {
description: "A document section reference identifier"
cddl: "section_ref"
@@ -55,17 +57,22 @@ metadataFormats: #metadataFormats & {
description: "A list of all versions of this document which are 'revoked'."
cddl: "revocations"
}
+ "Chain Link": {
+ description: "A link to a previous document in a chained sequence."
+ cddl: "chain"
+ }
}
// Types of a Metadata Fields
#metadataTypes: [
- for k, _ in metadataFormats {k},
+ for k, _ in metadata.formats {k},
]
// Constraint of Types of Metadata Fields
#metadataTypesConstraint: or(#metadataTypes)
// Canonical List of all valid metadata names
+// Must be listed in preferred order
_metadataNames: list.UniqueItems
_metadataNames: [
"type",
@@ -78,6 +85,7 @@ _metadataNames: [
"collaborators",
"revocations",
"parameters",
+ "chain",
]
_allMetadataNames: or([
@@ -98,19 +106,18 @@ _allMetadataNames: or([
}
// Markdown description of the field.
- description: string | *""
+ description: string
// Optional notes about validating the field.
- validation: string | *null
-
- // Is the field exclusive of another field (ie can not exist with that other field in the same document)
- exclusive: [..._allMetadataNames] | *null
+ validation: string
}
// Metadata fields that are optional
#metadataStruct: {
[_allMetadataNames]: #metadataField
}
-_metadata: #metadataStruct & {
+
+#metadata: #metadataStruct
+#metadata: {
// Document Type
type: {
required: "yes"
@@ -134,19 +141,6 @@ _metadata: #metadataStruct & {
`id` and `ver` being equal *MUST* exist.
"""
}
- // Document Version
- ver: {
- required: "yes"
- format: "Document Ver"
- description: """
- The unique version of the document.
- The first version of the document must set `ver` == `id`
- """
-
- validation: """
- The document version must always be >= the document ID.
- """
- }
ref: {
description: """
@@ -255,20 +249,11 @@ _metadata: #metadataStruct & {
"""
}
- parameters: {
- description: "A reference to the Parameters Document this document lies under."
- validation: """
- In addition to the validation performed for `Document Reference` type fields:
-
- * Any linked referenced document that includes a `parameters` metadata must match the
- `parameters` of the referencing document.
- """
- }
}
// Note: we make all normally excluded fields optional at the global level, because they are globally optional
-metadata: _metadata
-metadata: {
+metadata: headers: #metadata
+metadata: headers: {
ref: required: "optional"
ref: type: _allDocNamesList
template: required: "optional"
@@ -277,22 +262,9 @@ metadata: {
reply: type: #commentDocNamesList
section: required: "optional"
collaborators: required: "optional"
- parameters: required: "optional"
- parameters: type: #parameterDocNamesList
}
// Preferred display order
// If metadata field not listed, then list them after the explicit ones, in alphabetical order.
-metadata_order: list.UniqueItems
-metadata_order: [..._allMetadataNames] & [
- "type",
- "id",
- "ver",
- "ref",
- "template",
- "reply",
- "section",
- "collaborators",
- "revocations",
- "parameters",
-]
+metadata: order: list.UniqueItems
+metadata: order: [..._allMetadataNames] & _metadataNames
diff --git a/specs/definitions/signed_docs/metadata_chain.cue b/specs/definitions/signed_docs/metadata_chain.cue
new file mode 100644
index 0000000000..313f8313df
--- /dev/null
+++ b/specs/definitions/signed_docs/metadata_chain.cue
@@ -0,0 +1,89 @@
+// Signed Document Definitions
+//
+// Metadata Types and Constraints
+@extern(embed)
+package signed_docs
+
+_chainValidMermaid: _ @embed(file=includes/valid_chain.mermaid,type=text)
+_chainInvalidMermaid: _ @embed(file=includes/invalid_chain.mermaid,type=text)
+_chainFraudulentMermaid: _ @embed(file=includes/fraudulent_chain.mermaid,type=text)
+
+_chain_validation_common: """
+ Chained Documents do not support collaborators.
+ Any document which is attempted to be published in the sequence
+ which is *NOT* published by the author of the first document in the
+ sequence is fraudulent, and to be discarded.
+
+ In addition, the chained document *MUST*:
+
+ * Not have `collaborators`;
+ * Have the same `id` as the document being chained to;
+ * Have a `ver` that is greater than the `ver` being chained to;
+ * Have the same `type` as the chained document;
+ * Have `parameters` match;
+ * Have not be chaining to a document already chained to by another document;
+ * Have its absolute `height` exactly one more than the `height` of the document being chained to.
+
+ IF any of these validations fail, then the entire sequence of documents is INVALID.
+ Not just the current document.
+ """
+
+_chain_validation_examples: """
+ ##### Example of a Valid Chain
+
+
+ ``` mermaid
+ \(_chainValidMermaid)
+ ```
+
+
+ ##### Example of an Invalid Chain
+
+ Either of the two documents being present invalidates the data
+ in the entire chain,
+ as they are signed by the author of the chain.
+
+
+ ``` mermaid
+ \(_chainInvalidMermaid)
+ ```
+
+
+ ##### Example of a Fraudulent Chain Document
+
+ The invalid document does not invalidate the chain,
+ as its not signed by the author of the chained documents.
+
+
+ ``` mermaid
+ \(_chainFraudulentMermaid)
+ ```
+
+ """
+
+_chain_validation_complete: """
+ \(_chain_validation_common)
+
+ \(_chain_validation_examples)
+ """
+
+#metadata: chain: {
+ format: "Chain Link"
+ description: """
+ An immutable link to the previous document in a chained sequence of documents.
+ Because ID/Ver only defines values for the current document, and is not intended
+ by itself to prevent insertion of documents in a sequence, the `chain`
+ metadata allows for the latest document to directly point to its previous iteration.
+
+ It also aids in discoverability, where the latest document may be pinned but prior
+ documents can be discovered automatically by following the chain.
+ """
+ validation: string | *"""
+ \(_chain_validation_common)
+ """
+}
+
+metadata: headers: chain: {
+ required: "optional"
+ validation: _chain_validation_complete
+}
diff --git a/specs/definitions/signed_docs/metadata_parameters.cue b/specs/definitions/signed_docs/metadata_parameters.cue
new file mode 100644
index 0000000000..664ce5def6
--- /dev/null
+++ b/specs/definitions/signed_docs/metadata_parameters.cue
@@ -0,0 +1,55 @@
+// Signed Document Definitions
+//
+// Metadata Types and Constraints
+package signed_docs
+
+import (
+ "strings"
+)
+
+_metadata: _parameters: {
+ _description: """
+ A reference to the Parameters Document this document lies under.
+ """
+
+ _validation: """
+ In addition to the validation performed for `Document Reference` type fields:
+
+ * Any linked referenced document that includes a `parameters` metadata must match the
+ `parameters` of the referencing document,
+ or a parent of those `parameters`.
+
+ For example, a linked reference to `Contest Parameters` is transitively a reference to
+ the Parameters document it references, and each parameters document they reference
+ until the `Brand` parameters document is reached.
+
+ The use case here is for Templates.
+ The profile template, or proposal templates could be defined at any of these
+ levels, and as long as they all refer to the same chain of parameters in the
+ hierarchy they are all valid.
+ """
+}
+
+#metadata: parameters: {
+
+ description: string | *"""
+ \(_metadata._parameters._description)
+ """
+ validation: string | *"""
+ \(_metadata._parameters._validation)
+ """
+}
+
+// List of all Parameters Docs (not templates or actions)
+#parameterDocNamesList: [...string] & [
+ for k, _ in _allDocs
+ if strings.Contains(k, "Parameter") &&
+ !strings.Contains(k, "Template") &&
+ !strings.Contains(k, "Action") {k},
+]
+
+// Top Level general documentation for Parameters Metadata.
+metadata: headers: parameters: {
+ required: "optional"
+ type: #parameterDocNamesList
+}
diff --git a/specs/definitions/signed_docs/metadata_template.cue b/specs/definitions/signed_docs/metadata_template.cue
new file mode 100644
index 0000000000..3f77683cc3
--- /dev/null
+++ b/specs/definitions/signed_docs/metadata_template.cue
@@ -0,0 +1,35 @@
+// Signed Document Definitions
+//
+// Metadata Types and Constraints
+package signed_docs
+
+import (
+ "strings"
+)
+
+// List of all Template Docs (not actions)
+#templateDocNamesList: [...string] & [
+ for k, _ in _allDocs
+ if strings.Contains(k, "Template") &&
+ !strings.Contains(k, "Presentation") &&
+ !strings.Contains(k, "Action") {k},
+]
+
+_template_description: """
+ Reference to the template used to create and/or validate this document.
+ """
+_template_validation: """
+ In addition to the validation performed for `Document Reference` type fields,
+ The document payload is not valid if it does not validate completely against the referenced template.
+ """
+
+#metadata: template: {
+ description: _template_description
+ validation: _template_validation
+}
+
+// Note: we make all normally excluded fields optional at the global level, because they are globally optional
+metadata: headers: {
+ template: required: "optional"
+ template: type: #templateDocNamesList
+}
diff --git a/specs/definitions/signed_docs/metadata_ver.cue b/specs/definitions/signed_docs/metadata_ver.cue
new file mode 100644
index 0000000000..ec6e1c8980
--- /dev/null
+++ b/specs/definitions/signed_docs/metadata_ver.cue
@@ -0,0 +1,53 @@
+// Signed Document Definitions
+//
+// Metadata Types and Constraints
+// `ver`
+@extern(embed)
+package signed_docs
+
+_ver_description_common: """
+ The unique version of the document.
+ The first version of the document must set `ver` == `id`
+ """
+
+_ver_description_complete: """
+ \(_ver_description_common)
+
+ `ver` represents either:
+
+ * when a document changes over time, such as
+ with a new version of a particular document that supersedes an
+ earlier one.
+ * when a new document in a sequence of documents is produced.
+
+ Because the most common use `ver` is a new version of the same document
+ this is to be assumed unless the document specifies its representing
+ a sequence of documents.
+ """
+
+_ver_description_versioned: """
+ \(_ver_description_common)
+
+ `ver` represents new versions of the same document as it changes over time.
+ """
+
+_ver_description_sequenced: """
+ \(_ver_description_common)
+
+ `ver` represents new documents in a sequence of documents.
+ """
+
+// Document Version
+#metadata: {
+ ver: {
+ required: "yes"
+ format: "Document Ver"
+ description: string | *_ver_description_versioned
+ validation: """
+ The document version must always be >= the document ID.
+ """
+ }
+}
+
+// Note: we make all normally excluded fields optional at the global level, because they are globally optional
+metadata: headers: ver: description: _ver_description_complete
diff --git a/specs/definitions/signed_docs/payload.cue b/specs/definitions/signed_docs/payload.cue
new file mode 100644
index 0000000000..f302163be1
--- /dev/null
+++ b/specs/definitions/signed_docs/payload.cue
@@ -0,0 +1,33 @@
+package signed_docs
+
+import (
+ "list"
+)
+
+// Individual Payload Example
+#payloadExample: {
+ // Title of the example
+ title: string
+ // Expanded description of what the example shows.
+ description: string
+ // Example data that matches the payload schema.
+ example: _
+}
+
+// Payload definition
+_payload: {
+ // Description of the payload
+ description: string
+ // Is the Payload nil?
+ nil?: true
+
+ // Only have these when the payload isn't nil.
+ if nil == _|_ {
+ // Optional fixed schema for the payload.
+ // A URI or inline JSON Schema that the payload must validate against.
+ schema?: _
+ // Examples of the schema.
+ examples?: list.UniqueItems
+ examples?: [...#payloadExample] | *[]
+ }
+}
diff --git a/specs/signed_docs/signed_doc.cue b/specs/definitions/signed_docs/signed_doc.cue
similarity index 81%
rename from specs/signed_docs/signed_doc.cue
rename to specs/definitions/signed_docs/signed_doc.cue
index 0487238724..fbf1b15254 100644
--- a/specs/signed_docs/signed_doc.cue
+++ b/specs/definitions/signed_docs/signed_doc.cue
@@ -7,6 +7,7 @@ import (
"list"
"strings"
"github.com/input-output-hk/catalyst-libs/specs/generic:uuid"
+ "github.com/input-output-hk/catalyst-libs/specs/form_template/fields:form_template"
)
// Document Type must be a valid UUIDv4
@@ -34,11 +35,13 @@ import (
notes: [...string] | *[]
- // Fixed headers in every document
- headers: _coseHeaders
+ if payload.nil == _|_ {
+ // Fixed headers in every document with a payload.
+ headers: _coseHeaders
+ }
// The Metadata fields in this document (non cose standard)
- metadata: _metadata
+ metadata: #metadata
// Requirements for the document payload.
payload?: _payload
@@ -62,9 +65,7 @@ import (
// Customize each document type in its own `.cue` file.
docs: #DocumentDefinitions & {
for k, v in _allDocs {
- (k): {
- type: v
- }
+ (k): type: v
}
}
@@ -98,23 +99,10 @@ _allDocNamesList: [...string] & [
!strings.Contains(k, "Action") {k},
]
-// List of all Parameters Docs (not templates or actions)
-#parameterDocNamesList: [...string] & [
- for k, _ in _allDocs
- if strings.Contains(k, "Parameter") &&
- !strings.Contains(k, "Template") &&
- !strings.Contains(k, "Action") {k},
-]
-
-// List of all Template Docs (not actions)
-#templateDocNamesList: [...string] & [
- for k, _ in _allDocs
- if strings.Contains(k, "Template") &&
- !strings.Contains(k, "Action") {k},
-]
-
// List of all the document names we have defined.
_allDocNames: or(_allDocNamesList)
// Individual Valid Document Name constraint.
#DocumentName: _allDocNames
+
+formTemplate: form_template.dictionary
diff --git a/specs/signed_docs/signers.cue b/specs/definitions/signed_docs/signers.cue
similarity index 100%
rename from specs/signed_docs/signers.cue
rename to specs/definitions/signed_docs/signers.cue
diff --git a/specs/gen_docs/README.md b/specs/gen_docs/README.md
deleted file mode 100644
index fa54af1807..0000000000
--- a/specs/gen_docs/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Signed Documents documentation generator
-
-Builds Markdown and other documentation files from the signed documents specifications.
diff --git a/specs/gen_docs/__init__.py b/specs/gen_docs/__init__.py
deleted file mode 100644
index 332939cbf4..0000000000
--- a/specs/gen_docs/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# Intentionally Empty
-"""Doc Generation Program."""
diff --git a/specs/gen_docs/gen/cddl_file.py b/specs/gen_docs/gen/cddl_file.py
deleted file mode 100644
index c5a46af8b9..0000000000
--- a/specs/gen_docs/gen/cddl_file.py
+++ /dev/null
@@ -1,108 +0,0 @@
-"""Generate CDDL Files."""
-
-import argparse
-import re
-import textwrap
-
-from gen.doc_generator import DocGenerator
-from spec.signed_doc import SignedDoc
-
-
-def add_cddl_comments(comment: str) -> tuple[str, bool]:
- """Add cddl comment markers to lines.
-
- Returns True if more than 1 line.
- """
- comment = comment.strip()
- comment_lines = comment.splitlines()
- comment = ""
- for line in comment_lines:
- comment += f"; {line}\n"
- comment = comment.strip()
-
- return comment, len(comment_lines) > 0
-
-
-class CDDLFile(DocGenerator):
- """Generate a CDDL File."""
-
- def __init__(self, args: argparse.Namespace, spec: SignedDoc, cddl_root: str) -> None:
- """CDDL File Generator."""
- file_name = "cddl/" + cddl_root.lower().replace(" ", "_").replace("-", "_") + ".cddl"
-
- super().__init__(args, spec, file_name, flags=self.NO_FLAGS)
- self._cddl_root = cddl_root
-
- def get_cddl(self, name: str, found: list[str] | None = None) -> tuple[str, list[str]]:
- """Get the CDDL for a metadatum."""
- if found is None:
- found = []
-
- this_cddl = ""
- this_def = self._spec.cddl_def(name)
- cddl_def: str = this_def["def"].strip()
- cddl_def_multiline = len(cddl_def.splitlines()) > 1
-
- # Add required definitions to this one (recursive)
- for requires in this_def["requires"]:
- if requires not in found:
- next_cddl, found = self.get_cddl(requires, found)
- found.append(requires)
- this_cddl += next_cddl
-
- comment: str = this_def.get("comment", "")
- leading_comment = ""
- if len(comment) > 0:
- comment, multiline = add_cddl_comments(comment)
- if multiline or cddl_def_multiline:
- leading_comment = comment
- comment = "\n" # Adds a blank line after defs with multiline comments
-
- this_cddl = f"""
-{leading_comment}
-{name} = {cddl_def} {comment}
-
-{this_cddl}
-"""
-
- return this_cddl, found
-
- def markdown_reference(self, *, indent: int = 0, relative_doc: DocGenerator | None = None) -> str:
- """Create a Markdown formatted reference for the CDDL file."""
- file_path = self.file_path(relative_doc)
- file_name = self.file_name()
-
- return textwrap.indent(
- f"""
-
-??? note "CDDL Specification"
-
- * [{file_name}]({file_path})
-
- ```cddl
- {{{{ include_file('./{file_path}', indent={indent + 4}) }}}}
- ```
-
-
-""".strip(),
- " " * indent,
- )
-
- def generate(self) -> bool:
- """Generate a CDDL File."""
- cddl_data, _ = self.get_cddl(self._cddl_root)
- defs = self._spec.cddl_def(self._cddl_root)
-
- description, _ = add_cddl_comments(defs.get("description", f"{self._cddl_root}"))
-
- # Remove double line breaks,
- # so we only ever have 1 between definitions
- cddl_data = re.sub(r"\n\n[\n]+", "\n\n", cddl_data)
-
- self._filedata = f"""
-{description}
-
-
-{cddl_data.strip()}
-"""
- return super().generate()
diff --git a/specs/gen_docs/pyproject.toml b/specs/gen_docs/pyproject.toml
deleted file mode 100644
index 6626530ffb..0000000000
--- a/specs/gen_docs/pyproject.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[project]
-name = "gen-docs"
-version = "0.1.0"
-description = "Generate Signed Document documentation files."
-readme = "README.md"
-requires-python = ">=3.13"
-dependencies = [
- "pydantic>=2.11.4",
- "pydot>=3.0.4",
- "rich>=14.0.0",
- "rich-argparse>=1.7.0",
-]
-
-[tool.ruff]
-# Extend the project wide `ruff.toml` file.
-# Done so we can add known libraries to sorting.
-extend = "../../ruff.toml"
-
-[tool.ruff.lint.isort]
-known-third-party = [
- "pydantic",
- "pydot",
- "rich",
- "rich-argparse"
-]
-
-known-first-party = [
- "spec",
-]
diff --git a/specs/gen_docs/spec/cddl_definitions.py b/specs/gen_docs/spec/cddl_definitions.py
deleted file mode 100644
index 42276fa99b..0000000000
--- a/specs/gen_docs/spec/cddl_definitions.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""CDDL Definition Specification."""
-
-from pydantic import BaseModel, ConfigDict, Field
-
-
-class CDDLDefinition(BaseModel):
- """CDDL Definition Deserialized Specification."""
-
- definition: str = Field(alias="def")
- requires: list[str]
- description: str | None = Field(default=None)
- comment: str | None = Field(default=None)
-
- model_config = ConfigDict(extra="forbid")
diff --git a/specs/gen_docs/spec/content_types.py b/specs/gen_docs/spec/content_types.py
deleted file mode 100644
index 0efb7ae158..0000000000
--- a/specs/gen_docs/spec/content_types.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Content Types Specification."""
-
-from pydantic import BaseModel, ConfigDict, Field
-
-
-class ContentTypes(BaseModel):
- """Content Types Deserialized Specification."""
-
- description: str
- coap_type: int | None = Field(default=None)
-
- model_config = ConfigDict(extra="forbid")
-
-
-class EncodingTypes(BaseModel):
- """Encoding Types Deserialized Specification."""
-
- description: str
-
- model_config = ConfigDict(extra="forbid")
diff --git a/specs/gen_docs/spec/cose_header.py b/specs/gen_docs/spec/cose_header.py
deleted file mode 100644
index 17ef085e49..0000000000
--- a/specs/gen_docs/spec/cose_header.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Cose Header Specification."""
-
-from pydantic import BaseModel, ConfigDict, Field
-
-from spec.optional import OptionalField
-
-
-class CoseHeader(BaseModel):
- """Cose Header Deserialized Specification."""
-
- cose_label: str | int = Field(alias="coseLabel")
- description: str
- required: OptionalField
- format: str
- value: str | list[str] | None = Field(default=None)
-
- model_config = ConfigDict(extra="forbid")
diff --git a/specs/gen_docs/spec/doc_clusters.py b/specs/gen_docs/spec/doc_clusters.py
deleted file mode 100644
index d5c0e1f92d..0000000000
--- a/specs/gen_docs/spec/doc_clusters.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""CDDL Definition Specification."""
-
-from collections import Counter
-from functools import cached_property
-
-from pydantic import BaseModel, ConfigDict, PrivateAttr
-
-
-class DocCluster(BaseModel):
- """Document Cluster Deserialized Specification."""
-
- docs: list[str]
- _name: str | None = PrivateAttr(default=None)
-
- model_config = ConfigDict(extra="forbid")
-
- def is_cluster(self, match: list[str]) -> bool:
- """Is this list of strings matching this cluster."""
- return Counter(self.docs) == Counter(match)
-
- def is_in_cluster(self, match: str) -> bool:
- """Is this doc in this cluster."""
- return match in self.docs
-
- def set_name(self, name: str) -> None:
- """Set the clusters name."""
- self._name = name
-
- @cached_property
- def name(self) -> str:
- """Name."""
- return self._name
diff --git a/specs/gen_docs/spec/document.py b/specs/gen_docs/spec/document.py
deleted file mode 100644
index 1f9e8a9d39..0000000000
--- a/specs/gen_docs/spec/document.py
+++ /dev/null
@@ -1,84 +0,0 @@
-"""Individual Document Specification."""
-
-import typing
-
-from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
-
-from spec.change_log_entry import ChangeLogEntry
-from spec.cose_header import CoseHeader
-from spec.metadata import Metadata
-from spec.payload import Payload
-from spec.signers import Signers
-
-
-class DocumentBusinessLogic(BaseModel):
- """Document Business Logic Data Definition."""
-
- front_end: str | None = Field(default=None)
- back_end: str | None = Field(default=None)
-
- model_config = ConfigDict(extra="forbid")
-
-
-class Document(BaseModel):
- """Document Data Definition."""
-
- type: list[str]
- description: str | None = Field(default=None)
- validation: str | None = Field(default=None)
- business_logic: DocumentBusinessLogic = Field(
- default_factory=DocumentBusinessLogic,
- )
- notes: list[str]
- headers: dict[str, CoseHeader]
- metadata: dict[str, Metadata]
- payload: Payload | None = Field(default=None)
- signers: Signers
- authors: dict[str, str]
- versions: list[ChangeLogEntry]
-
- _name: str | None = PrivateAttr(default=None)
- _all_refs: list[str] = PrivateAttr(default_factory=list)
- _refed_by: list[str] = PrivateAttr(default_factory=list)
-
- doc_name: str | None = Field(default=None) # Set when wwe get a document
-
- model_config = ConfigDict(extra="forbid")
-
- def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
- """Extra setup after we deserialize."""
- super().model_post_init(context)
-
- # Set all the documents this references.
- all_refs: list[str] = []
- for meta in self.metadata.values():
- if meta.format == "Document Reference":
- all_refs.extend(meta.type)
- self._all_refs = list(set(all_refs))
-
- def set_name(self, doc_name: str) -> None:
- """Set the name properties."""
- self.doc_name = doc_name
-
- for name, meta in self.metadata.items():
- meta.set_name(name, doc_name)
-
- def add_referer(self, doc_name: str) -> None:
- """Set the name properties."""
- if doc_name not in self._refed_by:
- self._refed_by.append(doc_name)
-
- @property
- def all_references(self) -> list[str]:
- """Get a list of all documents this document references."""
- return self._all_refs
-
- @property
- def name(self) -> list[str]:
- """Get name of this document."""
- return self._name
-
- @property
- def all_docs_referencing(self) -> list[str]:
- """Get name of all documents which reference this document."""
- return self._refed_by
diff --git a/specs/gen_docs/spec/metadata.py b/specs/gen_docs/spec/metadata.py
deleted file mode 100644
index 8109545c2c..0000000000
--- a/specs/gen_docs/spec/metadata.py
+++ /dev/null
@@ -1,178 +0,0 @@
-"""Metadata Field Specification."""
-
-from functools import cached_property
-
-from pydantic import BaseModel, ConfigDict, Field, computed_field
-
-from spec.optional import OptionalField
-
-
-class Metadata(BaseModel):
- """Metadata Spec Data Definition."""
-
- description: str
- raw_exclusive: list[str] | None = Field(alias="exclusive")
- format: str
- required: OptionalField
- validation: str | None
- raw_type: str | list[str] | None = Field(alias="type", default=None)
- multiple: bool = Field(default=False)
- raw_linked_refs: list[str] | None = Field(alias="linked_refs", default=None)
-
- # Not deserialized, must be supplied.
- name: str | None = Field(default=None) # Comes from `new`.
- doc_name: str | None = Field(default=None)
-
- model_config = ConfigDict(extra="forbid")
-
- def set_name(self, name: str, doc_name: str | None = None) -> None:
- """Set the name properties."""
- self.name = name
- self.doc_name = doc_name
-
- @staticmethod
- def fix_list(fix: str | list[str] | None) -> list[str]:
- """Fix up the named field, so it only has a list."""
- if fix is None:
- fix = []
- if isinstance(fix, str):
- fix = [fix]
- return fix
-
- @computed_field()
- @cached_property
- def exclusive(self) -> list[str]:
- """Exclusive."""
- return self.fix_list(self.raw_exclusive)
-
- @computed_field()
- @cached_property
- def type(self) -> list[str]:
- """Type."""
- return self.fix_list(self.raw_type)
-
- @computed_field()
- @cached_property
- def linked_refs(self) -> list[str]:
- """Linked Refs."""
- return self.fix_list(self.raw_linked_refs)
-
- @staticmethod
- def doc_ref_link(name: str, depth: int = 0, *, html: bool = False) -> str:
- """Metadata Document Reference link."""
- link = name.lower().replace(" ", "_")
-
- if html:
- link += "/"
- else:
- link += ".md"
-
- if depth == 0:
- link = f"./docs/{link}"
- else:
- maxdepth = 0 if html else 1
- while depth > maxdepth:
- link = f"../{link}"
- depth -= 1
-
- if html:
- return link
- return f"[{name}]({link})"
-
- @staticmethod
- def format_link(name: str, depth: int = 0) -> str:
- """Metadata Format link."""
- link = f"metadata.md#{name.lower().replace(' ', '-')}"
-
- while depth > 0:
- link = f"../{link}"
- depth -= 1
-
- return f"[{name}]({link})"
-
- @staticmethod
- def field_link(name: str, depth: int = 0) -> str:
- """Metadata Field link."""
- link = f"metadata.md#{name.lower().replace('`', '')}"
-
- while depth > 0:
- link = f"../{link}"
- depth -= 1
-
- return f"[`{name}`]({link})"
-
- def get_validation(self) -> str:
- """Get the Validation documentation (enhanced from the data itself)."""
- # Adds text to the validation description, so get it here.
- validation = self.validation
-
- # Add notes about exclusive field relationships.
- if len(self.exclusive) > 0:
- exclusive_def = f"\n`{self.exclusive[0]}`"
- if len(self.exclusive) > 1:
- if len(self.exclusive) > 2: # noqa: PLR2004
- for exclude in self.exclusive[1:-1]:
- # We break the line so it doesn't get too long.
- exclusive_def += f"\n, `{exclude}`"
-
- exclusive_def += f"\nand `{self.exclusive[-1]}`"
- validation += f"\n* MUST NOT be present in any document that contains {exclusive_def} metadata."
-
- for ref in self.linked_refs:
- validation += f"""
-* The Document referenced by `{ref}`
- * MUST contain `{self.name}` metadata; AND
- * MUST match the referencing documents `{self.name}` value."""
-
- return validation.strip()
-
- def is_excluded(self) -> bool:
- """Is this metadata excluded from the specs definition. (must not be present)."""
- return self.required == "excluded"
-
- def metadata_as_markdown(self, *, doc_types: list[str] | None = None) -> str:
- """Generate Markdown of Metadata fields for the default set, or a specific document."""
- field_title_level = "###"
-
- field_display = f"""
-{field_title_level} `{self.name}`
-
-
-| Parameter | Value |
-| --- | --- |
-| Required | {self.required.value} |
-"""
- if not self.is_excluded():
- field_display += f"| Format | `{self.format}` |\n"
-
- if self.name == "type" and doc_types is not None:
- # Display the actual documents type values
- monospace_types = [f"`{doc_type}`" for doc_type in doc_types]
- field_display += f"| Type | {', '.join(monospace_types)} |\n"
-
- if self.multiple:
- field_display += f"| Multiple References | {self.multiple} |\n"
-
- ref_heading = "Valid References"
- for ref_doc in self.type:
- field_display += f"| {ref_heading} | `{ref_doc}` |\n"
- ref_heading = ""
-
- ref_heading = "Linked Reference Metadata"
- for ref_field in self.linked_refs:
- field_display += f"| {ref_heading} | [`{ref_field}`](#{ref_field}) |\n"
- ref_heading = ""
-
- exclusive_title = "Exclusive"
- for ref in self.exclusive:
- field_display += f"| {exclusive_title} | `{ref}` |\n"
- exclusive_title = ""
-
- field_display += f"""
-{self.description}
-
-{field_title_level}# `{self.name}` Validation
-
-{self.get_validation()}
-"""
- return field_display
diff --git a/specs/gen_docs/spec/metadata_formats.py b/specs/gen_docs/spec/metadata_formats.py
deleted file mode 100644
index 87a3fb925f..0000000000
--- a/specs/gen_docs/spec/metadata_formats.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""Metadata Formats Specification."""
-
-from pydantic import BaseModel, ConfigDict
-
-
-class MetadataFormats(BaseModel):
- """Metadata Formats Deserialized Specification."""
-
- description: str
- cddl: str
-
- model_config = ConfigDict(extra="forbid")
diff --git a/specs/gen_docs/spec/payload.py b/specs/gen_docs/spec/payload.py
deleted file mode 100644
index 732682508c..0000000000
--- a/specs/gen_docs/spec/payload.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Payload Specification."""
-
-from typing import Any
-
-from pydantic import BaseModel, ConfigDict, Field, HttpUrl
-
-
-class Payload(BaseModel):
- """Payload Deserialized Specification."""
-
- description: str
- doc_schema: HttpUrl | dict[str, Any] | None = Field(default=None, alias="schema")
-
- model_config = ConfigDict(extra="forbid")
diff --git a/specs/gen_docs/spec/signed_doc.py b/specs/gen_docs/spec/signed_doc.py
deleted file mode 100644
index e9f832b361..0000000000
--- a/specs/gen_docs/spec/signed_doc.py
+++ /dev/null
@@ -1,353 +0,0 @@
-"""Signed Document Specification."""
-
-# Autogenerate Documentation Pages from the formal specification
-
-import datetime
-import json
-import textwrap
-import typing
-from enum import Enum
-from pathlib import Path
-
-from pydantic import BaseModel, ConfigDict, Field, HttpUrl
-
-from spec.cddl_definitions import CDDLDefinition
-from spec.change_log_entry import ChangeLogEntry
-from spec.content_types import ContentTypes, EncodingTypes
-from spec.copyright import Copyright
-from spec.cose_header import CoseHeader
-from spec.doc_clusters import DocCluster
-from spec.document import Document
-from spec.metadata import Metadata
-from spec.metadata_formats import MetadataFormats
-from spec.optional import OptionalField
-
-
-class HeaderType(Enum):
- """All header Types."""
-
- DOCUMENT = 1
- SIGNATURE = 2
- METADATA = 3
-
-
-HEADERS: dict[str, dict[str, str]] = {
- HeaderType.DOCUMENT: {
- "headers": "cose_headers",
- "order": "cose_headers_order",
- "format": "coseHeaderFormats",
- },
- HeaderType.SIGNATURE: {
- "headers": "cose_signature_headers",
- "order": "cose_signature_headers_order",
- "format": "coseHeaderFormats",
- },
- HeaderType.METADATA: {
- "headers": "metadata",
- "order": "metadata_order",
- "format": "metadataFormats",
- },
-}
-
-
-class SignedDoc(BaseModel):
- """Signed Doc Deserialized Specification."""
-
- authors: dict[str, str]
- base_types: dict[str, str]
- cddl_definitions: dict[str, CDDLDefinition] = Field(alias="cddlDefinitions")
- content_types: dict[str, ContentTypes] = Field(alias="contentTypes")
- copyright: Copyright
- cose_header_formats: dict[str, MetadataFormats] = Field(alias="coseHeaderFormats")
- cose_headers: dict[str, CoseHeader]
- cose_headers_order: list[str]
- cose_signature_headers: dict[str, CoseHeader]
- doc_clusters: dict[str, DocCluster]
- docs: dict[str, Document]
- documentation_links: dict[str, HttpUrl] = Field(alias="documentationLinks")
- encoding_types: dict[str, EncodingTypes] = Field(alias="encodingTypes")
- link_aka: dict[str, str] = Field(alias="linkAKA")
- metadata: dict[str, Metadata]
- metadata_formats: dict[str, MetadataFormats] = Field(alias="metadataFormats")
- metadata_order: list[str]
-
- _data: dict[str, typing.Any]
- _file: str
-
- model_config = ConfigDict(extra="forbid")
-
- @classmethod
- def load(cls, spec_file: str) -> typing.Self:
- """Initialize the Signed Document Specification."""
- with Path(spec_file).open("r") as f:
- data: dict = json.load(f)
- doc = cls(**data)
- doc._data = data
- doc._file = spec_file
- return doc
-
- def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
- """Extra setup after we deserialize."""
- super().model_post_init(context)
-
- # Set the name in each cluster.
- for cluster, value in self.doc_clusters.items():
- value.set_name(cluster)
-
- # Set the name and references for each document.
- for name, doc in self.docs.items():
- doc.set_name(name)
- for ref_doc in doc.all_references:
- self.docs[ref_doc].add_referer(name)
-
- def ref_in_cluster(self, ref: list[str]) -> DocCluster | None:
- """Get the cluster a document is in, if any."""
- for cluster in self.doc_clusters.values():
- if cluster.is_cluster(ref):
- return cluster
- return None
-
- def doc_in_cluster(self, doc_name: str) -> DocCluster | None:
- """Is the named document in a cluster."""
- for cluster in self.doc_clusters.values():
- if cluster.is_in_cluster(doc_name):
- return cluster
- return None
-
- def doc_in_cluster_name(self, doc_name: str) -> str | None:
- """Is the named document in a cluster of what name."""
- for cluster in self.doc_clusters.values():
- if cluster.is_in_cluster(doc_name):
- return cluster.name
- return None
-
- def data(self) -> dict:
- """Return the raw spec data."""
- return self._data
-
- def document_names(self) -> list[str]:
- """Get all documents."""
- return self.docs.keys()
-
- def format_names(self, header_type: HeaderType) -> list[str]:
- """Get a list of all metadata format names defined."""
- _, _, formats = self.headers_and_order(header_type=header_type)
- metadata_formats: dict = self._data[formats]
- return metadata_formats.keys()
-
- def link_name_aka(self, link_name: str) -> str | None:
- """Get a Link AKA for a link name, or None if it doesn't exist."""
- return self.link_aka.get(link_name)
-
- def link_names(self) -> list[str]:
- """Get a list of ALL link names, including AKAs.
-
- Sorted from longest Link name to shortest.
- """
- link_aka: list[str] = list(self.link_aka.keys())
- primary_links: list[str] = list(self.documentation_links.keys())
-
- return sorted(link_aka + primary_links, key=lambda x: -len(x))
-
- def link_for_link_name(self, link_name: str) -> str:
- """Get a link for a link name."""
- return self.documentation_links[link_name]
-
- def header(self, header: str, header_type: HeaderType = HeaderType.DOCUMENT) -> dict:
- """Get Cose header definition."""
- headers, _, _ = self.headers_and_order(header_type)
- return headers[header]
-
- def content_type_description(self, content_type: str) -> str:
- """Get a description for a known content type."""
- return self.content_types[content_type].description
-
- def encoding_type_description(self, encoding_type: str) -> str:
- """Get a description for a known content type."""
- return self.encoding_types[encoding_type].description
-
- def headers_and_order(self, header_type: HeaderType) -> tuple[dict, list[str], str]:
- """Get headers and their ordering for a header_type."""
- headers = HEADERS[header_type]["headers"]
- header_order = HEADERS[header_type]["order"]
- formats = HEADERS[header_type]["format"]
-
- headers: dict = self._data[headers]
- header_order: list[str] = self._data.get(header_order, [])
-
- # Make sure unordered headers get included in the documentation.
- for header in headers:
- if header not in header_order:
- header_order.append(header)
-
- return (headers, header_order, formats)
-
- def all_headers(self, header_type: HeaderType = HeaderType.DOCUMENT) -> list[str]:
- """Return a list of sorted Cose headers."""
- _, header_order, _ = self.headers_and_order(header_type)
- return header_order
-
- def cddl_type_for_metadata(self, name: str | None, header_type: str) -> str:
- """Get the CDDL type for a given Metadata field."""
- headers, _, formats = self.headers_and_order(header_type)
-
- cddl_def = headers.get(name)
- if cddl_def is not None:
- cddl_def = cddl_def.get("format")
- if cddl_def is not None:
- cddl_def = self._data[formats].get(cddl_def)
- if cddl_def is not None:
- cddl_def = cddl_def.get("cddl")
- return cddl_def
-
- def cddl_def(self, name: str) -> dict | None: # noqa: C901
- """Get a cddl definition by name."""
-
- def synthetic_headers(defs: dict, header_type: HeaderType = HeaderType.METADATA) -> dict:
- """Generate a synthetic cddl def for this type.
-
- Needs to be generated from Metadata definitions.
- """
- cddl_def = ""
- defs["requires"] = []
- exclusives = []
-
- headers, header_names, _ = self.headers_and_order(header_type)
-
- for header in header_names:
- header_data = headers[header]
- optional = "" if header_data["required"] == "yes" else "?"
-
- exclusive: list[str] | None = header_data.get("exclusive")
- if exclusive is not None:
- exclusive.append(header)
- exclusive.sort()
- if exclusive not in exclusives:
- exclusives.append(exclusive)
- else:
- cddl_type = self.cddl_type_for_metadata(header, header_type)
- field_name = header_data.get("coseLabel", header)
- if isinstance(field_name, str):
- field_name = f'"{field_name}"'
- cddl_def += f"{optional}{field_name} => {cddl_type}\n"
- if cddl_type not in defs["requires"]:
- defs["requires"].append(cddl_type)
- for exclusive_set in exclusives:
- # Exclusive sets are never required
- exclusive_fields = []
- for entry in exclusive_set:
- cddl_type = self.cddl_type_for_metadata(entry, header_type)
- field_name = headers[entry].get("coseLabel", entry)
- if isinstance(field_name, str):
- field_name = f'"{field_name}"'
- exclusive_fields.append(f"{field_name} => {cddl_type}")
- if cddl_type not in defs["requires"]:
- defs["requires"].append(cddl_type)
-
- cddl_def += f"""? (
- {" //\n ".join(exclusive_fields)}
-)
-""".strip()
- defs["def"] = f"(\n{textwrap.indent(cddl_def, ' ')})"
- return defs
-
- defs = self._data.get("cddlDefinitions")
- if defs is not None:
- defs = defs.get(name)
- if name == "Signed_Document_Metadata_Headers":
- defs = synthetic_headers(defs, HeaderType.METADATA)
- elif name == "COSE_Document_Standard_Headers":
- defs = synthetic_headers(defs, HeaderType.DOCUMENT)
- elif name == "COSE_Signature_Standard_Headers":
- defs = synthetic_headers(defs, HeaderType.SIGNATURE)
- return defs
-
- def get_copyright(
- self,
- document_name: str | None,
- ) -> tuple[dict[str, str], Copyright, list[ChangeLogEntry], datetime.date]:
- """Get copyright information from the spec."""
-
- def get_latest_file_change(
- versions: list[ChangeLogEntry], doc_versions: list[ChangeLogEntry] | None
- ) -> datetime.date:
- """Get the largest document version date."""
- latest_date = datetime.date.fromtimestamp(0.0) # noqa: DTZ012
- for ver in versions:
- latest_date = max(latest_date, ver.modified)
-
- if doc_versions is not None:
- for ver in doc_versions:
- latest_date = max(latest_date, ver.modified)
-
- return latest_date
-
- authors = self.authors
- copyright_data = self.copyright
- versions = copyright_data.versions
-
- doc_versions = None
- if document_name is not None:
- doc = self.docs[document_name]
- authors = doc.authors | authors
- doc_versions = doc.versions
-
- latest_change = get_latest_file_change(versions, doc_versions)
- if doc_versions is not None:
- versions = doc_versions
-
- return (authors, copyright_data, versions, latest_change)
-
- def base_document_types(self) -> dict[str, str]:
- """Get the base document types."""
- return self.base_types
-
- def document_type(self, doc_name: str) -> list[str]:
- """Get the types for a specific document."""
- return self.docs[doc_name].type
-
- def doc_name_for_type(self, uuid: str) -> str:
- """Get the name for a document base type, given its uuid."""
- doc_types = self.base_document_types()
- for k, v in doc_types.items():
- if v == uuid:
- return k
- return "Unknown"
-
- def get_document(self, doc_name: str) -> Document:
- """Get a named document."""
- doc = self.docs[doc_name]
- doc.set_name(doc_name)
- return doc
-
- def get_metadata(self, metadata_name: str, doc_name: str | None = None) -> Metadata:
- """Get a metadata definition by name, and optionally for a document."""
- if doc_name is None:
- raw_metadata_def = self.metadata[metadata_name]
- else:
- raw_metadata_def = self.docs[doc_name].metadata[metadata_name]
- raw_metadata_def.set_name(metadata_name, doc_name)
- return raw_metadata_def
-
- def get_all_metadata_formats(self) -> list[str]:
- """Get a list of all metadata formats defined."""
- return self._data["metadataFormats"].keys()
-
- def get_metadata_format(self, format_name: str) -> MetadataFormats:
- """Get a metadata format definition by name."""
- return self.metadata_formats[format_name]
-
- def get_metadata_as_markdown(self, doc_name: str | None = None) -> str:
- """Get metadata definitions in a markdown format."""
- fields = self.all_headers(HeaderType.METADATA)
- field_display = ""
- for field in fields:
- doc_types = None
- if doc_name is not None:
- doc_types = self.get_document(doc_name).type
- metadata_def = self.get_metadata(field, doc_name)
- if doc_name is None or metadata_def.required != OptionalField.excluded:
- field_display += metadata_def.metadata_as_markdown(
- doc_types=doc_types,
- )
- return field_display.strip()
diff --git a/specs/gen_docs/uv.lock b/specs/gen_docs/uv.lock
deleted file mode 100644
index 5a05c6644e..0000000000
--- a/specs/gen_docs/uv.lock
+++ /dev/null
@@ -1,171 +0,0 @@
-version = 1
-revision = 2
-requires-python = ">=3.13"
-
-[[package]]
-name = "annotated-types"
-version = "0.7.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload_time = "2024-05-20T21:33:25.928Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload_time = "2024-05-20T21:33:24.1Z" },
-]
-
-[[package]]
-name = "gen-docs"
-version = "0.1.0"
-source = { virtual = "." }
-dependencies = [
- { name = "pydantic" },
- { name = "pydot" },
- { name = "rich" },
- { name = "rich-argparse" },
-]
-
-[package.metadata]
-requires-dist = [
- { name = "pydantic", specifier = ">=2.11.4" },
- { name = "pydot", specifier = ">=3.0.4" },
- { name = "rich", specifier = ">=14.0.0" },
- { name = "rich-argparse", specifier = ">=1.7.0" },
-]
-
-[[package]]
-name = "markdown-it-py"
-version = "3.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "mdurl" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload_time = "2023-06-03T06:41:14.443Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload_time = "2023-06-03T06:41:11.019Z" },
-]
-
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload_time = "2022-08-14T12:40:10.846Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload_time = "2022-08-14T12:40:09.779Z" },
-]
-
-[[package]]
-name = "pydantic"
-version = "2.11.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "annotated-types" },
- { name = "pydantic-core" },
- { name = "typing-extensions" },
- { name = "typing-inspection" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/77/ab/5250d56ad03884ab5efd07f734203943c8a8ab40d551e208af81d0257bf2/pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d", size = 786540, upload_time = "2025-04-29T20:38:55.02Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e7/12/46b65f3534d099349e38ef6ec98b1a5a81f42536d17e0ba382c28c67ba67/pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb", size = 443900, upload_time = "2025-04-29T20:38:52.724Z" },
-]
-
-[[package]]
-name = "pydantic-core"
-version = "2.33.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload_time = "2025-04-23T18:33:52.104Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload_time = "2025-04-23T18:31:53.175Z" },
- { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload_time = "2025-04-23T18:31:54.79Z" },
- { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload_time = "2025-04-23T18:31:57.393Z" },
- { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload_time = "2025-04-23T18:31:59.065Z" },
- { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload_time = "2025-04-23T18:32:00.78Z" },
- { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload_time = "2025-04-23T18:32:02.418Z" },
- { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload_time = "2025-04-23T18:32:04.152Z" },
- { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload_time = "2025-04-23T18:32:06.129Z" },
- { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload_time = "2025-04-23T18:32:08.178Z" },
- { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload_time = "2025-04-23T18:32:10.242Z" },
- { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload_time = "2025-04-23T18:32:12.382Z" },
- { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload_time = "2025-04-23T18:32:14.034Z" },
- { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload_time = "2025-04-23T18:32:15.783Z" },
- { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload_time = "2025-04-23T18:32:18.473Z" },
- { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload_time = "2025-04-23T18:32:20.188Z" },
- { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload_time = "2025-04-23T18:32:22.354Z" },
- { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload_time = "2025-04-23T18:32:25.088Z" },
-]
-
-[[package]]
-name = "pydot"
-version = "3.0.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pyparsing" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/66/dd/e0e6a4fb84c22050f6a9701ad9fd6a67ef82faa7ba97b97eb6fdc6b49b34/pydot-3.0.4.tar.gz", hash = "sha256:3ce88b2558f3808b0376f22bfa6c263909e1c3981e2a7b629b65b451eee4a25d", size = 168167, upload_time = "2025-01-05T16:18:45.763Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b0/5f/1ebfd430df05c4f9e438dd3313c4456eab937d976f6ab8ce81a98f9fb381/pydot-3.0.4-py3-none-any.whl", hash = "sha256:bfa9c3fc0c44ba1d132adce131802d7df00429d1a79cc0346b0a5cd374dbe9c6", size = 35776, upload_time = "2025-01-05T16:18:42.836Z" },
-]
-
-[[package]]
-name = "pygments"
-version = "2.19.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload_time = "2025-01-06T17:26:30.443Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload_time = "2025-01-06T17:26:25.553Z" },
-]
-
-[[package]]
-name = "pyparsing"
-version = "3.2.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload_time = "2025-03-25T05:01:28.114Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload_time = "2025-03-25T05:01:24.908Z" },
-]
-
-[[package]]
-name = "rich"
-version = "14.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "markdown-it-py" },
- { name = "pygments" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload_time = "2025-03-30T14:15:14.23Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload_time = "2025-03-30T14:15:12.283Z" },
-]
-
-[[package]]
-name = "rich-argparse"
-version = "1.7.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "rich" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/aa/b9/ff53663ee7fa6a4195fa96d91da499f2e00ca067541e016d345cce1c9ad2/rich_argparse-1.7.0.tar.gz", hash = "sha256:f31d809c465ee43f367d599ccaf88b73bc2c4d75d74ed43f2d538838c53544ba", size = 38009, upload_time = "2025-02-08T19:00:20.755Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bb/9c/dc7cbeb99a7b7422392ed7f327efdbb958bc0faf424aef5f130309320bda/rich_argparse-1.7.0-py3-none-any.whl", hash = "sha256:b8ec8943588e9731967f4f97b735b03dc127c416f480a083060433a97baf2fd3", size = 25339, upload_time = "2025-02-08T19:00:17.911Z" },
-]
-
-[[package]]
-name = "typing-extensions"
-version = "4.13.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload_time = "2025-04-10T14:19:05.416Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload_time = "2025-04-10T14:19:03.967Z" },
-]
-
-[[package]]
-name = "typing-inspection"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222, upload_time = "2025-02-25T17:27:59.638Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125, upload_time = "2025-02-25T17:27:57.754Z" },
-]
diff --git a/specs/gen_docs/.python-version b/specs/generators/.python-version
similarity index 100%
rename from specs/gen_docs/.python-version
rename to specs/generators/.python-version
diff --git a/specs/generators/packages/spec/.python-version b/specs/generators/packages/spec/.python-version
new file mode 100644
index 0000000000..24ee5b1be9
--- /dev/null
+++ b/specs/generators/packages/spec/.python-version
@@ -0,0 +1 @@
+3.13
diff --git a/specs/generators/packages/spec/README.md b/specs/generators/packages/spec/README.md
new file mode 100644
index 0000000000..1b94098f25
--- /dev/null
+++ b/specs/generators/packages/spec/README.md
@@ -0,0 +1 @@
+# Interpreted Specification Library
diff --git a/specs/generators/packages/spec/pyproject.toml b/specs/generators/packages/spec/pyproject.toml
new file mode 100644
index 0000000000..f6396ccf16
--- /dev/null
+++ b/specs/generators/packages/spec/pyproject.toml
@@ -0,0 +1,17 @@
+[project]
+name = "spec"
+version = "0.1.0"
+description = "Interpreted Specification Library"
+readme = "README.md"
+authors = [
+ { name = "Steven Johnson", email = "steven.joshnson@iohk.io" }
+]
+requires-python = ">=3.13"
+dependencies = []
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/spec"]
\ No newline at end of file
diff --git a/specs/gen_docs/spec/__init__.py b/specs/generators/packages/spec/src/spec/__init__.py
similarity index 50%
rename from specs/gen_docs/spec/__init__.py
rename to specs/generators/packages/spec/src/spec/__init__.py
index 16ad0890f5..241c60cc2b 100644
--- a/specs/gen_docs/spec/__init__.py
+++ b/specs/generators/packages/spec/src/spec/__init__.py
@@ -1,2 +1,3 @@
-# Intentionally Empty
"""Spec Definition Module."""
+
+# Intentionally Empty File.
diff --git a/specs/generators/packages/spec/src/spec/authors.py b/specs/generators/packages/spec/src/spec/authors.py
new file mode 100644
index 0000000000..09c1443a25
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/authors.py
@@ -0,0 +1,22 @@
+"""Change Log Entry Specification."""
+
+from pydantic import RootModel
+
+
+class Authors(RootModel[dict[str, str]]):
+ """Authors of the Specifications."""
+
+ root: dict[str, str] # name: email
+
+ def combine(self, other: "Authors") -> "Authors":
+ """Combine Two Authors lists into a single Authors List."""
+ combined = self.root | other.root
+ return self.model_validate(combined)
+
+ def email(self, name: str) -> str:
+ """Get Email for authors name."""
+ return self.root.get(name, "Unknown")
+
+ def all(self) -> list[str]:
+ """Get All Authors."""
+ return sorted(self.root.keys())
diff --git a/specs/generators/packages/spec/src/spec/base_types.py b/specs/generators/packages/spec/src/spec/base_types.py
new file mode 100644
index 0000000000..7a076e9b9d
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/base_types.py
@@ -0,0 +1,60 @@
+"""Base Document Type Identifiers."""
+
+import typing
+
+from pydantic import RootModel, computed_field
+from pydantic.types import UUID4
+
+
+class DocTypeId(RootModel[UUID4]):
+ """Document Type ID is a UUIDv4."""
+
+ root: UUID4 # name: uuid_str
+
+ class Config:
+ """Config."""
+
+ frozen = True
+
+ @computed_field
+ @property
+ def as_cbor(self) -> str:
+ """DocType in CBOR Diagnostic Notation."""
+ return f"37(h'{self.root.hex}')"
+
+ @computed_field
+ @property
+ def as_uuid_str(self) -> str:
+ """DocType in CBOR Diagnostic Notation."""
+ return str(self.root)
+
+
+class BaseTypes(RootModel[dict[str, DocTypeId]]):
+ """Authors of the Specifications."""
+
+ root: dict[str, DocTypeId] # name: uuid_str
+
+ _for_uuid: dict[DocTypeId, str] # reverse lookup
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set all the documents this references.
+ self._for_uuid = {}
+ for k, v in self.root.items():
+ self._for_uuid[v] = k
+
+ def uuid(self, name: str) -> DocTypeId:
+ """Get UUID for Base Type Name."""
+ return self.root[name]
+
+ def name(self, uuid: DocTypeId) -> str:
+ """Get Base Type Name for the given UUID."""
+ return self._for_uuid[uuid]
+
+ @computed_field
+ @property
+ def all(self) -> list[str]:
+ """Get All Base Types."""
+ return sorted(self.root.keys())
diff --git a/specs/generators/packages/spec/src/spec/cddl/__init__.py b/specs/generators/packages/spec/src/spec/cddl/__init__.py
new file mode 100644
index 0000000000..104d9cd342
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/cddl/__init__.py
@@ -0,0 +1,3 @@
+"""Spec - CDDL - Definition Module."""
+
+# Intentionally Empty File.
diff --git a/specs/generators/packages/spec/src/spec/cddl/cose.py b/specs/generators/packages/spec/src/spec/cddl/cose.py
new file mode 100644
index 0000000000..566a91dbae
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/cddl/cose.py
@@ -0,0 +1,123 @@
+"""Cose CDDL Definitions."""
+
+import typing
+from enum import Enum
+from functools import cached_property
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, RootModel, computed_field
+
+from spec.metadata_formats import MetadataFormats
+from spec.optional import OptionalField
+
+
+class HeaderType(Enum):
+ """All header Types."""
+
+ DOCUMENT = 1
+ SIGNATURE = 2
+ METADATA = 3
+
+
+class GenericHeader(BaseModel):
+ """Generic Cose/Metadata header."""
+
+ cose_label: str | int | None = Field(default=None, alias="coseLabel")
+ description: str
+ required: OptionalField
+ format: str
+
+ _name: str = PrivateAttr(default="Unknown")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def name(self) -> str:
+ """Get headers name."""
+ return self._name
+
+ def set_name(self, name: str) -> None:
+ """Set headers name."""
+ self._name = name
+
+ @computed_field
+ @property
+ def label(self) -> str:
+ """Get headers name."""
+ if self.cose_label is None:
+ return f'"{self._name}"'
+ if isinstance(self.cose_label, str):
+ return f'"{self.cose_label}"'
+ return f"{self.cose_label}"
+
+
+class CoseHeader(GenericHeader):
+ """Cose Header Deserialized Specification."""
+
+ value: str | list[str] | None = Field(default=None)
+
+ model_config = ConfigDict(extra="forbid")
+
+
+class CoseHeaders(RootModel[dict[str, CoseHeader]]):
+ """Cose Headers."""
+
+ root: dict[str, CoseHeader]
+
+ _order: list[str] | None = PrivateAttr(default=None)
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set Cose Header Names
+ for name, header in self.root.items():
+ header.set_name(name)
+
+ def get(self, name: str) -> CoseHeader:
+ """Get a Cose Header by its name."""
+ return self.root[name]
+
+ @computed_field
+ @cached_property
+ def all(self) -> list[CoseHeader]:
+ """Get all Cose Headers sorted and in a list."""
+ return [self.get(name) for name in self.names]
+
+ @computed_field
+ @property
+ def names(self) -> list[str]:
+ """Get ordered list of all defined Cose Header Names."""
+ if self._order is not None:
+ return self._order
+ return list(self.root.keys())
+
+ def order(self, order: list[str]) -> None:
+ """Set the order of fields."""
+ tmp_order = order
+ # Add in any unlisted headers
+ for name in self.root:
+ if name not in tmp_order:
+ tmp_order.append(name)
+ self._order = []
+ # remove any listed headers that are not used.
+ for name in tmp_order:
+ if name in self.root:
+ self._order.append(name)
+
+
+class CoseDefinitions(BaseModel):
+ """Definitions of our COSE Format usage."""
+
+ header_formats: MetadataFormats = Field(alias="headerFormats")
+ headers: CoseHeaders
+ headers_order: list[str] = Field(alias="headersOrder") # dont use directly
+ signature_headers: CoseHeaders
+
+ model_config = ConfigDict(extra="forbid")
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set Cose Header Order
+ self.headers.order(self.headers_order)
+ self.signature_headers.order(self.headers_order)
diff --git a/specs/generators/packages/spec/src/spec/cddl/definition.py b/specs/generators/packages/spec/src/spec/cddl/definition.py
new file mode 100644
index 0000000000..704b11ae6e
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/cddl/definition.py
@@ -0,0 +1,116 @@
+"""CDDL Definition Specification."""
+
+import re
+import typing
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, RootModel
+
+
+class CDDLDefinition(BaseModel):
+ """CDDL Definition Deserialized Specification."""
+
+ definition: str = Field(alias="def")
+ requires: list[str]
+ description: str | None = Field(default=None)
+ comment: str = Field(default_factory=str)
+
+ _name: str = PrivateAttr(default="Unknown")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def name(self) -> str:
+ """Name Of the Parameter."""
+ return self._name
+
+ def set_name(self, val: str) -> None:
+ """Set Name."""
+ self._name = val
+
+
+class CDDLDefinitions(RootModel[dict[str, CDDLDefinition]]):
+ """Template Json Schema Definitions."""
+
+ root: dict[str, CDDLDefinition]
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ for def_name, value in self.root.items():
+ value.set_name(def_name)
+
+ def get(self, name: str) -> CDDLDefinition:
+ """Get a CDDL Definition."""
+ return self.root[name]
+
+ def add(self, definition: CDDLDefinition | list[CDDLDefinition]) -> None:
+ """Add (or change) a definitions to the CDDL Definitions."""
+ if isinstance(definition, CDDLDefinition):
+ definition = [definition]
+ for this_def in definition:
+ self.root[this_def.name()] = this_def
+
+ @staticmethod
+ def _add_cddl_comments(comment: str) -> tuple[str, bool]:
+ """Add cddl comment markers to lines.
+
+ Returns True if more than 1 line.
+ """
+ comment = comment.strip()
+ comment_lines = comment.splitlines()
+ comment = ""
+ for line in comment_lines:
+ comment += f"; {line}\n"
+ comment = comment.strip()
+
+ return comment, len(comment_lines) > 0
+
+ def _nested_cddl(self, name: str, found: list[str]) -> tuple[str, list[str]]:
+ """Get the CDDL for a names definition, recursively."""
+ this_cddl = ""
+ this_def = self.get(name)
+ cddl_def = this_def.definition.strip()
+ cddl_def_multiline = len(cddl_def.splitlines()) > 1
+
+ # Add required definitions to this one (recursive)
+ for requires in this_def.requires:
+ if requires not in found:
+ next_cddl, found = self._nested_cddl(requires, found)
+ found.append(requires)
+ this_cddl += next_cddl
+
+ comment: str = this_def.comment
+ leading_comment = ""
+ if len(comment) > 0:
+ comment, multiline = self._add_cddl_comments(comment)
+ if multiline or cddl_def_multiline:
+ leading_comment = comment
+ comment = "\n" # Adds a blank line after defs with multiline comments
+
+ this_cddl = f"""
+{leading_comment}
+{name} = {cddl_def} {comment}
+
+{this_cddl}
+"""
+
+ return this_cddl, found
+
+ def cddl_file(self, root: str) -> str:
+ """Get the CDDL File for a root definition with a given name."""
+ cddl_data = self._nested_cddl(root, [])[0]
+ description = self.get(root).description
+ if description is None:
+ description = root
+ description = self._add_cddl_comments(description)[0]
+
+ # Remove double line breaks,
+ # so we only ever have 1 between definitions
+ cddl_data = re.sub(r"\n\n[\n]+", "\n\n", cddl_data)
+
+ return f"""
+{description}
+
+
+{cddl_data.strip()}
+"""
diff --git a/specs/gen_docs/spec/change_log_entry.py b/specs/generators/packages/spec/src/spec/change_log_entry.py
similarity index 100%
rename from specs/gen_docs/spec/change_log_entry.py
rename to specs/generators/packages/spec/src/spec/change_log_entry.py
diff --git a/specs/generators/packages/spec/src/spec/content_types.py b/specs/generators/packages/spec/src/spec/content_types.py
new file mode 100644
index 0000000000..6dcdab8189
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/content_types.py
@@ -0,0 +1,40 @@
+"""Content Types Specification."""
+
+from pydantic import BaseModel, ConfigDict, Field, RootModel
+
+
+class ContentType(BaseModel):
+ """Content Types Deserialized Specification."""
+
+ description: str
+ coap_type: int | None = Field(default=None)
+
+ model_config = ConfigDict(extra="forbid")
+
+
+class ContentTypes(RootModel[dict[str, ContentType]]):
+ """Content Types Deserialized Specification."""
+
+ root: dict[str, ContentType]
+
+ def description(self, name: str) -> str:
+ """Get description of the Content Type."""
+ return self.root[name].description
+
+
+class EncodingType(BaseModel):
+ """Encoding Types Deserialized Specification."""
+
+ description: str
+
+ model_config = ConfigDict(extra="forbid")
+
+
+class EncodingTypes(RootModel[dict[str, EncodingType]]):
+ """Content Types Deserialized Specification."""
+
+ root: dict[str, EncodingType]
+
+ def description(self, name: str) -> str:
+ """Get description of the Encoding Type."""
+ return self.root[name].description
diff --git a/specs/gen_docs/spec/copyright.py b/specs/generators/packages/spec/src/spec/copyright.py
similarity index 100%
rename from specs/gen_docs/spec/copyright.py
rename to specs/generators/packages/spec/src/spec/copyright.py
diff --git a/specs/generators/packages/spec/src/spec/doc_clusters.py b/specs/generators/packages/spec/src/spec/doc_clusters.py
new file mode 100644
index 0000000000..b926407a2f
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/doc_clusters.py
@@ -0,0 +1,68 @@
+"""CDDL Definition Specification."""
+
+import typing
+from collections import Counter
+from functools import cached_property
+
+from pydantic import BaseModel, ConfigDict, PrivateAttr, RootModel
+
+
+class DocCluster(BaseModel):
+ """Document Cluster Deserialized Specification."""
+
+ docs: list[str]
+ _name: str = PrivateAttr(default="Unknown")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def is_cluster(self, match: list[str]) -> bool:
+ """Is this list of strings matching this cluster."""
+ return Counter(self.docs) == Counter(match)
+
+ def is_in_cluster(self, match: str) -> bool:
+ """Is this doc in this cluster."""
+ return match in self.docs
+
+ def set_name(self, name: str) -> None:
+ """Set the clusters name."""
+ self._name = name
+
+ @cached_property
+ def name(self) -> str:
+ """Name."""
+ return self._name
+
+
+class DocClusters(RootModel[dict[str, DocCluster]]):
+ """All Document Clusters."""
+
+ root: dict[str, DocCluster]
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set the name in each cluster.
+ for cluster, value in self.root.items():
+ value.set_name(cluster)
+
+ def for_ref(self, ref: list[str]) -> DocCluster | None:
+ """Get the cluster a document is in, if any."""
+ for cluster in self.root.values():
+ if cluster.is_cluster(ref):
+ return cluster
+ return None
+
+ def get(self, doc_name: str) -> DocCluster | None:
+ """Is the named document in a cluster."""
+ for cluster in self.root.values():
+ if cluster.is_in_cluster(doc_name):
+ return cluster
+ return None
+
+ def name(self, doc_name: str) -> str | None:
+ """Is the named document in a cluster of what name."""
+ for cluster in self.root.values():
+ if cluster.is_in_cluster(doc_name):
+ return cluster.name
+ return None
diff --git a/specs/generators/packages/spec/src/spec/doc_types.py b/specs/generators/packages/spec/src/spec/doc_types.py
new file mode 100644
index 0000000000..225602d3f7
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/doc_types.py
@@ -0,0 +1,39 @@
+"""Document Types."""
+
+from pydantic import RootModel
+
+from spec.base_types import BaseTypes, DocTypeId
+
+
+class DocType(RootModel[list[DocTypeId]]):
+ """A Document Type."""
+
+ root: list[DocTypeId]
+
+ _base_types: BaseTypes
+
+ def set_base_types(self, types: BaseTypes) -> None:
+ """Save a local copy of the Base Types."""
+ self._base_types = types
+
+ def formatted_names(self, *, prefix: str = "", separator: str = "/", suffix: str = "") -> str:
+ """Return a formatted doc types entry."""
+ type_names: list[str] = [self._base_types.name(sub_type) for sub_type in self.root]
+ return f"{prefix}{separator.join(type_names)}{suffix}"
+
+ def formatted_ids( # noqa: PLR0913
+ self,
+ *,
+ prefix: str = "[",
+ separator: str = ",",
+ start_quote: str = "",
+ end_quote: str = "",
+ suffix: str = "]",
+ cbor: bool = True,
+ ) -> str:
+ """Return doc types formatted optionally as cbor."""
+ id_strings: list[str] = (
+ [uuid.as_cbor for uuid in self.root] if cbor else [uuid.as_uuid_str for uuid in self.root]
+ )
+ id_strings = [f"{start_quote}{ids}{end_quote}" for ids in id_strings]
+ return f"{prefix}{separator.join(id_strings)}{suffix}"
diff --git a/specs/generators/packages/spec/src/spec/document.py b/specs/generators/packages/spec/src/spec/document.py
new file mode 100644
index 0000000000..a7788f6fe7
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/document.py
@@ -0,0 +1,141 @@
+"""Individual Document Specification."""
+
+import typing
+from functools import cached_property
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, RootModel, computed_field
+
+from spec.authors import Authors
+from spec.base_types import BaseTypes
+from spec.cddl.cose import CoseHeaders
+from spec.change_log_entry import ChangeLogEntry
+from spec.doc_types import DocType
+from spec.metadata import MetadataHeaders
+from spec.payload import Payload
+from spec.signers import Signers
+
+
+class DocumentBusinessLogic(BaseModel):
+ """Document Business Logic Data Definition."""
+
+ front_end: str | None = Field(default=None)
+ back_end: str | None = Field(default=None)
+
+ model_config = ConfigDict(extra="forbid")
+
+
+def empty_string_list() -> list[str]:
+ """Get an empty string list."""
+ return []
+
+
+class Document(BaseModel):
+ """Document Data Definition."""
+
+ type: DocType
+ description: str | None = Field(default=None)
+ validation: str | None = Field(default=None)
+ business_logic: DocumentBusinessLogic = Field(
+ default_factory=DocumentBusinessLogic,
+ )
+ notes: list[str]
+ headers: CoseHeaders | None = Field(default=None)
+ metadata: MetadataHeaders
+ payload: Payload | None = Field(default=None)
+ signers: Signers
+ authors: Authors
+ versions: list[ChangeLogEntry]
+
+ _name: str | None = PrivateAttr(default=None)
+ _all_refs: list[str] = PrivateAttr(default_factory=empty_string_list)
+ _refed_by: list[str] = PrivateAttr(default_factory=empty_string_list)
+
+ doc_name: str | None = Field(default=None) # Set when wwe get a document
+
+ model_config = ConfigDict(extra="forbid")
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set all the documents this references.
+ all_refs: list[str] = []
+ for name in self.metadata.names:
+ meta = self.metadata.get(name)
+ if meta.format == "Document Reference":
+ all_refs.extend(meta.type)
+ self._all_refs = list(set(all_refs))
+
+ def set_base_types(self, types: BaseTypes) -> None:
+ """Save a local copy of the Base Types."""
+ self.type.set_base_types(types)
+
+ def set_name(self, doc_name: str) -> None:
+ """Set the name properties."""
+ self.doc_name = doc_name
+ self.metadata.set_name(doc_name)
+
+ def add_referer(self, doc_name: str) -> None:
+ """Set the name properties."""
+ if doc_name not in self._refed_by:
+ self._refed_by.append(doc_name)
+
+ @property
+ def all_references(self) -> list[str]:
+ """Get a list of all documents this document references."""
+ return self._all_refs
+
+ @property
+ def name(self) -> str:
+ """Get name of this document."""
+ return self._name if self._name is not None else "Unknown"
+
+ @property
+ def all_docs_referencing(self) -> list[str]:
+ """Get name of all documents which reference this document."""
+ return self._refed_by
+
+ @property
+ def content_type(self) -> str | list[str]:
+ """Get document content type."""
+ if self.headers is None:
+ return "Undefined"
+ content_type = self.headers.get("content type")
+ if content_type.value is None:
+ return "Undefined"
+ return content_type.value
+
+
+class Documents(RootModel[dict[str, Document]]):
+ """All Documents."""
+
+ root: dict[str, Document]
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set the name and references for each document.
+ for name, doc in self.root.items():
+ doc.set_name(name)
+ for ref_doc in doc.all_references:
+ self.root[ref_doc].add_referer(name)
+
+ def set_base_types(self, types: BaseTypes) -> None:
+ """Save a local copy of the Base Types."""
+ for doc in self.root.values():
+ doc.set_base_types(types)
+
+ def get(self, name: str) -> Document:
+ """Get a document by its name."""
+ return self.root[name]
+
+ @computed_field
+ @cached_property
+ def names(self) -> list[str]:
+ """Get all documents."""
+ return list(self.root.keys())
+
+ def type(self, doc_name: str) -> DocType:
+ """Get the types for a specific document."""
+ return self.root[doc_name].type
diff --git a/specs/generators/packages/spec/src/spec/documentation_links.py b/specs/generators/packages/spec/src/spec/documentation_links.py
new file mode 100644
index 0000000000..89419eba13
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/documentation_links.py
@@ -0,0 +1,59 @@
+"""Documentation Links."""
+
+import typing
+
+from pydantic import BaseModel, ConfigDict, Field, HttpUrl, RootModel, computed_field
+
+
+class LinkAKA(RootModel[dict[str, str]]):
+ """Link AKA."""
+
+ root: dict[str, str]
+
+
+class Links(RootModel[dict[str, HttpUrl]]):
+ """Documentation Links."""
+
+ root: dict[str, HttpUrl]
+
+ _aka: LinkAKA
+
+ def set_link_aka(self, aka: LinkAKA) -> None:
+ """Associate the Link AKA with the main documentation Links."""
+ self._aka = aka
+
+ def aka(self, link_name: str) -> str | None:
+ """Get a Link AKA for a link name, or None if it doesn't exist."""
+ return self._aka.root.get(link_name)
+
+ @computed_field
+ @property
+ def all(self) -> list[str]:
+ """Get a list of ALL link names, including AKAs.
+
+ Sorted from longest Link name to shortest.
+ """
+ link_aka: list[str] = list(self._aka.root.keys())
+ primary_links: list[str] = list(self.root.keys())
+
+ return sorted(link_aka + primary_links, key=lambda x: -len(x))
+
+ def link(self, link_name: str) -> str:
+ """Get a link for a link name."""
+ return f"{self.root[link_name]}"
+
+
+class Documentation(BaseModel):
+ """Documentation Information."""
+
+ links: Links
+ link_aka: LinkAKA = Field(alias="linkAKA")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Associate the Link AKA with documentation links.
+ self.links.set_link_aka(self.link_aka)
diff --git a/specs/generators/packages/spec/src/spec/forms/__init__.py b/specs/generators/packages/spec/src/spec/forms/__init__.py
new file mode 100644
index 0000000000..e0dcc786dc
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/forms/__init__.py
@@ -0,0 +1,3 @@
+"""Spec - Forms - Definition Module."""
+
+# Intentionally Empty File.
diff --git a/specs/generators/packages/spec/src/spec/forms/element/__init__.py b/specs/generators/packages/spec/src/spec/forms/element/__init__.py
new file mode 100644
index 0000000000..e0dcc786dc
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/forms/element/__init__.py
@@ -0,0 +1,3 @@
+"""Spec - Forms - Definition Module."""
+
+# Intentionally Empty File.
diff --git a/specs/generators/packages/spec/src/spec/forms/element/element.py b/specs/generators/packages/spec/src/spec/forms/element/element.py
new file mode 100644
index 0000000000..c40046faab
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/forms/element/element.py
@@ -0,0 +1,45 @@
+"""Form Template Definition."""
+
+from functools import cached_property
+from typing import Any
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, computed_field
+
+from spec.forms.element.parameters import Parameters
+
+
+class Element(BaseModel):
+ """Specification of an individual Form Element."""
+
+ description: str
+ definition: dict[str, Any] # Raw definition from JSON
+ parameters: Parameters
+ parent: str | None = Field(default=None)
+ _name: str = PrivateAttr(default="Unknown")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def name(self) -> str:
+ """Name Of the Parameter."""
+ return self._name
+
+ def set_name(self, val: str) -> None:
+ """Set Name."""
+ self._name = val
+
+ @computed_field
+ @cached_property
+ def json_definition(self) -> dict[str, Any]:
+ """Json Definition."""
+ return self.definition
+
+ @computed_field
+ @cached_property
+ def example(self) -> dict[str, Any]:
+ """Generate an example of the definition."""
+ name = self._name
+ example_name = "example" + name[0].upper() + name[1:]
+ example: dict[str, Any] = {example_name: self.parameters.example}
+ example["$ref"] = f"#/$defs/{name}"
+
+ return example
diff --git a/specs/generators/packages/spec/src/spec/forms/element/parameters.py b/specs/generators/packages/spec/src/spec/forms/element/parameters.py
new file mode 100644
index 0000000000..8d42dc775e
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/forms/element/parameters.py
@@ -0,0 +1,94 @@
+"""Form Template Definition."""
+
+import typing
+from functools import cached_property
+from typing import Any
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, RootModel, computed_field
+
+from spec.optional import OptionalField
+
+
+class Parameter(BaseModel):
+ """Specification of a single Json Schema Template Definition.
+
+ Models `specs/definitions/form_template/parameters.cue:#parameter`
+ """
+
+ property: str | None = Field(default=None)
+ description: str
+ required: OptionalField
+ type: str
+ items: "None | Parameter" = Field(default=None)
+ choices: list[str] | list[int] | None = Field(default=None)
+ format: str | None = Field(default=None)
+ content_media_type: str | None = Field(default=None, alias="contentMediaType")
+ pattern: str | None = Field(default=None)
+ min_length: int | None = Field(default=None)
+ minimum: int | None = Field(default=None)
+ maximum: int | None = Field(default=None)
+ example: Any = Field(default=None)
+
+ _name: str = PrivateAttr(default="Unknown")
+ _element_name: str = PrivateAttr(default="Unknown")
+
+ model_config = ConfigDict(extra="forbid")
+
+ def element_name(self) -> str:
+ """Name Of the Parameters Element Type."""
+ return self._element_name
+
+ def set_element_name(self, val: str) -> None:
+ """Set Element Name."""
+ self._element_name = val
+
+ def name(self) -> str:
+ """Name Of the Parameter."""
+ return self._name
+
+ def set_name(self, val: str) -> None:
+ """Set Name."""
+ self._name = val
+
+ def example_kv(self, index: int = 0) -> tuple[str, Any]:
+ """Generate an example value of the parameter."""
+ prop = self.property if self.property is not None else "Unknown"
+ value: dict[Any, Any] | str = {}
+ if self.type == "string":
+ value = f"An Example String {index}"
+
+ return (prop, value)
+
+
+class Parameters(RootModel[dict[str, Parameter]]):
+ """All Parameters defined for an Element."""
+
+ root: dict[str, Parameter]
+ _element_name: str = PrivateAttr(default="Unknown")
+
+ def element_name(self) -> str | None:
+ """Name Of the Parameters Element Type."""
+ return self._element_name
+
+ def set_element_name(self, val: str) -> None:
+ """Set Element Name."""
+ self._element_name = val
+ for name, value in self.root.items():
+ value.set_element_name(name)
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ for name, value in self.root.items():
+ value.set_name(name)
+
+ @computed_field
+ @cached_property
+ def example(self) -> dict[str, Any]:
+ """Generate an example of the definition."""
+ example: dict[str, Any] = {}
+
+ for name, value in self.root.items():
+ example[name] = value.example
+ return example
diff --git a/specs/generators/packages/spec/src/spec/forms/template.py b/specs/generators/packages/spec/src/spec/forms/template.py
new file mode 100644
index 0000000000..8c0e94993c
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/forms/template.py
@@ -0,0 +1,44 @@
+"""Form Template Definition."""
+
+import typing
+from functools import cached_property
+from typing import Any
+
+from pydantic import RootModel, computed_field
+
+from spec.forms.element.element import Element
+
+
+class FormTemplate(RootModel[dict[str, Element]]):
+ """Template Json Schema Definitions."""
+
+ root: dict[str, Element]
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ for def_name, value in self.root.items():
+ value.set_name(def_name)
+
+ @computed_field
+ @cached_property
+ def json_definition(self) -> dict[str, Any]:
+ """Json Definition."""
+ definitions: dict[str, Any] = {}
+
+ for k, v in self.root.items():
+ definitions[k] = v.json_definition
+
+ return definitions
+
+ @computed_field
+ @cached_property
+ def example(self) -> dict[str, Any]:
+ """Generate an example of the definitions."""
+ examples: dict[str, Any] = {}
+
+ for k, v in self.root.items():
+ examples[k] = v.example
+
+ return examples
diff --git a/specs/generators/packages/spec/src/spec/hello.py b/specs/generators/packages/spec/src/spec/hello.py
new file mode 100644
index 0000000000..8262099a66
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/hello.py
@@ -0,0 +1,6 @@
+"""Test."""
+
+
+def get_hello_world() -> str:
+ """Test."""
+ return "Hello World from spec!"
diff --git a/specs/generators/packages/spec/src/spec/metadata.py b/specs/generators/packages/spec/src/spec/metadata.py
new file mode 100644
index 0000000000..b41c9ef96b
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/metadata.py
@@ -0,0 +1,208 @@
+"""Metadata Field Specification."""
+
+import textwrap
+import typing
+from functools import cached_property
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, RootModel, computed_field
+
+from spec.cddl.cose import GenericHeader
+from spec.cddl.definition import CDDLDefinition
+from spec.document import DocType
+from spec.metadata_formats import MetadataFormats
+from spec.optional import OptionalField
+
+
+class MetadataHeader(GenericHeader):
+ """Metadata Spec Data Definition."""
+
+ validation: str | None
+ raw_type: str | list[str] | None = Field(alias="type", default=None)
+ multiple: bool = Field(default=False)
+ raw_linked_refs: list[str] | None = Field(alias="linked_refs", default=None)
+
+ # Not deserialized, must be supplied.
+ _name: str = PrivateAttr(default="Unknown")
+ _doc_name: str | None = PrivateAttr(default=None)
+
+ model_config = ConfigDict(extra="forbid")
+
+ def set_name(self, name: str, doc_name: str | None = None) -> None:
+ """Set the name properties."""
+ self._name = name
+ self._doc_name = doc_name
+
+ @staticmethod
+ def fix_list(fix: str | list[str] | None) -> list[str]:
+ """Fix up the named field, so it only has a list."""
+ if fix is None:
+ fix = []
+ if isinstance(fix, str):
+ fix = [fix]
+ return fix
+
+ @computed_field
+ @cached_property
+ def type(self) -> list[str]:
+ """Type."""
+ return self.fix_list(self.raw_type)
+
+ @computed_field
+ @cached_property
+ def linked_refs(self) -> list[str]:
+ """Linked Refs."""
+ return self.fix_list(self.raw_linked_refs)
+
+ def get_validation(self) -> str:
+ """Get the Validation documentation (enhanced from the data itself)."""
+ # Adds text to the validation description, so get it here.
+ validation = self.validation if self.validation is not None else ""
+
+ for ref in self.linked_refs:
+ validation += f"""
+
+* The Document referenced by `{ref}`
+ * MUST contain `{self._name}` metadata; AND
+ * MUST match the referencing documents `{self._name}` value."""
+
+ return validation.strip()
+
+ def is_excluded(self) -> bool:
+ """Is this metadata excluded from the specs definition. (must not be present)."""
+ return self.required == "excluded"
+
+ def metadata_as_markdown(self, *, doc_types: DocType | None = None) -> str:
+ """Generate Markdown of Metadata fields for the default set, or a specific document."""
+ field_title_level = "###"
+
+ field_display = f"""
+{field_title_level} `{self._name}`
+
+
+| Parameter | Value |
+| --- | --- |
+| Required | {self.required.value} |
+"""
+ if not self.is_excluded():
+ field_display += f"| Format | `{self.format}` |\n"
+
+ if self._name == "type" and doc_types is not None:
+ # Display the actual documents type values
+ formatted_id = doc_types.formatted_ids(
+ prefix="", start_quote="`", end_quote="`", separator=", ", suffix="", cbor=False
+ )
+ field_display += f"| Type | {formatted_id} |\n"
+
+ if self.multiple:
+ field_display += f"| Multiple References | {self.multiple} |\n"
+
+ ref_heading = "Valid References"
+ for ref_doc in self.type:
+ field_display += f"| {ref_heading} | `{ref_doc}` |\n"
+ ref_heading = ""
+
+ ref_heading = "Linked Reference Metadata"
+ for ref_field in self.linked_refs:
+ field_display += f"| {ref_heading} | [`{ref_field}`](#{ref_field}) |\n"
+ ref_heading = ""
+
+ field_display += f"""
+{self.description}
+
+{field_title_level}# `{self._name}` Validation
+
+{self.get_validation()}
+"""
+ return field_display
+
+
+class MetadataHeaders(RootModel[dict[str, MetadataHeader]]):
+ """All Metadata Headers."""
+
+ root: dict[str, MetadataHeader]
+
+ _order: list[str] | None = PrivateAttr(default=None)
+ _doc_name: str | None = PrivateAttr(default=None)
+
+ def get(self, name: str) -> MetadataHeader:
+ """Get a Metadata Header by its name."""
+ return self.root[name]
+
+ @computed_field
+ @property
+ def names(self) -> list[str]:
+ """Get ordered list of all defined Metadata Header Names."""
+ if self._order is not None:
+ return self._order
+ return list(self.root.keys())
+
+ @computed_field
+ @property
+ def all(self) -> typing.Sequence[MetadataHeader]:
+ """Get all metadata headers, in order."""
+ return [self.root[header] for header in self.names]
+
+ def order(self, order: list[str]) -> None:
+ """Set the order of fields."""
+ tmp_order = order
+ # Add in any unlisted headers
+ for name in self.root:
+ if name not in tmp_order:
+ tmp_order.append(name)
+ self._order = []
+ # remove any listed headers that are not used.
+ for name in tmp_order:
+ if name in self.root:
+ self._order.append(name)
+
+ def set_name(self, doc_name: str | None = None) -> None:
+ """Set the name properties."""
+ self._doc_name = doc_name
+ for name, header in self.root.items():
+ header.set_name(name, doc_name)
+
+
+class Metadata(BaseModel):
+ """Metadata Fields in the COSE Document."""
+
+ headers: MetadataHeaders
+ formats: MetadataFormats
+ order: list[str]
+
+ _doc_name: str | None = PrivateAttr(default=None)
+
+ model_config = ConfigDict(extra="forbid")
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Set Header Order
+ self.headers.order(self.order)
+
+ def set_name(self, doc_name: str | None = None) -> None:
+ """Set the name properties."""
+ self._doc_name = doc_name
+ self.headers.set_name(doc_name)
+
+ @staticmethod
+ def custom_metadata_header(
+ cddl_def: CDDLDefinition, headers: typing.Sequence[GenericHeader], formats: MetadataFormats
+ ) -> CDDLDefinition:
+ """Generate a synthetic cddl def for this type.
+
+ Needs to be generated from Metadata definitions.
+ """
+ new_def = cddl_def.model_copy()
+ new_def.requires = []
+ new_cddl: str = ""
+
+ for header in headers:
+ optional = "" if header.required == OptionalField.required else "?"
+ cddl_type = formats.get(header.format).cddl
+ new_cddl += f"{optional}{header.label} => {cddl_type}\n"
+ if cddl_type not in new_def.requires:
+ new_def.requires.append(cddl_type)
+
+ new_def.definition = f"(\n{textwrap.indent(new_cddl, ' ')})"
+ return new_def
diff --git a/specs/generators/packages/spec/src/spec/metadata_formats.py b/specs/generators/packages/spec/src/spec/metadata_formats.py
new file mode 100644
index 0000000000..86eb349cfb
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/metadata_formats.py
@@ -0,0 +1,27 @@
+"""Metadata Formats Specification."""
+
+from pydantic import BaseModel, ConfigDict, RootModel
+
+
+class MetadataFormat(BaseModel):
+ """Metadata Formats Deserialized Specification."""
+
+ description: str
+ cddl: str
+
+ model_config = ConfigDict(extra="forbid")
+
+
+class MetadataFormats(RootModel[dict[str, MetadataFormat]]):
+ """Metadata Formats Deserialized Specification."""
+
+ root: dict[str, MetadataFormat]
+
+ @property
+ def all(self) -> list[str]:
+ """Get names of all metadata formats."""
+ return list(self.root.keys())
+
+ def get(self, name: str) -> MetadataFormat:
+ """Get named metadata format."""
+ return self.root[name]
diff --git a/specs/gen_docs/spec/optional.py b/specs/generators/packages/spec/src/spec/optional.py
similarity index 100%
rename from specs/gen_docs/spec/optional.py
rename to specs/generators/packages/spec/src/spec/optional.py
diff --git a/specs/generators/packages/spec/src/spec/payload.py b/specs/generators/packages/spec/src/spec/payload.py
new file mode 100644
index 0000000000..3cce36578f
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/payload.py
@@ -0,0 +1,138 @@
+"""Payload Specification."""
+
+import json
+import textwrap
+import urllib
+import urllib.request
+from typing import Any
+
+import jsonschema
+import rich
+from pydantic import BaseModel, ConfigDict, Field, HttpUrl
+
+
+class PayloadExample(BaseModel):
+ """An Example of the payload."""
+
+ title: str
+ description: str
+ example: dict[str, Any]
+
+ model_config = ConfigDict(extra="forbid")
+
+ @classmethod
+ def default(cls) -> list["PayloadExample"]:
+ """Return Default list."""
+ return []
+
+ def __str__(self) -> str:
+ """Get the example properly formatted as markdown."""
+ example = json.dumps(self.example, indent=2, sort_keys=True)
+ textwrap.indent(example, " ")
+
+ return f"""
+
+
+??? example "Example: {self.title}"
+
+{textwrap.indent(self.description, " ")}
+
+ ```json
+{textwrap.indent(example, " ")}
+ ```
+
+
+""".strip()
+
+
+class SchemaValidationError(Exception):
+ """Something is wrong with payload schema validation."""
+
+
+class Payload(BaseModel):
+ """Payload Deserialized Specification."""
+
+ description: str
+ nil: bool = Field(default=False)
+ doc_schema: HttpUrl | dict[str, Any] | None = Field(default=None, alias="schema")
+ examples: list[PayloadExample] = Field(default_factory=PayloadExample.default)
+
+ model_config = ConfigDict(extra="forbid")
+
+ def model_post_init(self, context: Any) -> None: # noqa: ANN401
+ """Validate the examples against the schema."""
+ schema = None
+ validator = None
+ if isinstance(self.doc_schema, HttpUrl):
+ if f"{self.doc_schema}" == "https://json-schema.org/draft-07/schema":
+ schema = jsonschema.Draft7Validator.META_SCHEMA
+ elif f"{self.doc_schema}" == "https://json-schema.org/draft/2020-12/schema":
+ schema = jsonschema.Draft202012Validator.META_SCHEMA
+ else:
+ rich.print(f"Downloading Schema from: {self.doc_schema}")
+ with urllib.request.urlopen(f"{self.doc_schema}") as response: # noqa: S310
+ schema = json.loads(response.read())
+ elif isinstance(self.doc_schema, dict):
+ schema = self.doc_schema
+
+ if schema is not None:
+ # Check that its valid jsonschema Draft 7 or 202012.
+ try:
+ jsonschema.Draft7Validator.check_schema(schema)
+ validator = jsonschema.Draft7Validator(schema, format_checker=jsonschema.draft7_format_checker)
+ except: # noqa: E722
+ jsonschema.Draft202012Validator.check_schema(schema)
+ validator = jsonschema.Draft202012Validator(
+ schema, format_checker=jsonschema.draft202012_format_checker
+ )
+
+ for example in self.examples:
+ if validator is None:
+ msg = "No schema to validate payload examples."
+ raise SchemaValidationError(msg)
+ validator.validate(instance=example.example) # type: ignore # noqa: PGH003
+
+ return super().model_post_init(context)
+
+ def __str__(self) -> str:
+ """Get the examples properly formatted as markdown."""
+ docs = self.description + "\n"
+
+ if self.nil:
+ docs += """
+This document has no payload.
+It must be encoded as a CBOR `null (0xf6)`.
+"""
+ return docs.strip()
+
+ schema = self.doc_schema
+ if schema is not None:
+ if isinstance(schema, HttpUrl):
+ if schema == "https://json-schema.org/draft-07/schema":
+ docs += "\n**Must be a valid JSON Schema Draft 7 document.**"
+ else:
+ docs += f"\nMust be a valid according to <{schema}>."
+ else:
+ docs += f"""\n### Schema
+
+
+??? abstract
+
+{textwrap.indent(self.description, " ")}
+
+ ```json
+{textwrap.indent(json.dumps(schema, indent=2, sort_keys=True), " ")}
+ ```
+
+
+"""
+
+ if len(self.examples) > 0:
+ docs += "\n### Example"
+ if len(self.examples) >= 2: # noqa: PLR2004
+ docs += "s"
+ docs += "\n"
+ for example in self.examples:
+ docs += f"{example}\n"
+
+ return docs.strip()
diff --git a/specs/generators/packages/spec/src/spec/signed_doc.py b/specs/generators/packages/spec/src/spec/signed_doc.py
new file mode 100644
index 0000000000..82860e4ff1
--- /dev/null
+++ b/specs/generators/packages/spec/src/spec/signed_doc.py
@@ -0,0 +1,142 @@
+"""Signed Document Specification."""
+
+# Autogenerate Documentation Pages from the formal specification
+
+import datetime
+import typing
+from pathlib import Path
+
+from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
+
+from spec.authors import Authors
+from spec.base_types import BaseTypes
+from spec.cddl.cose import CoseDefinitions
+from spec.cddl.definition import CDDLDefinitions
+from spec.change_log_entry import ChangeLogEntry
+from spec.content_types import ContentTypes, EncodingTypes
+from spec.copyright import Copyright
+from spec.doc_clusters import DocClusters
+from spec.document import Documents
+from spec.documentation_links import Documentation
+from spec.forms.template import FormTemplate
+from spec.metadata import Metadata, MetadataHeader
+from spec.optional import OptionalField
+
+
+class SignedDoc(BaseModel):
+ """Signed Doc Deserialized Specification."""
+
+ authors: Authors
+ base_types: BaseTypes
+ cddl_definitions: CDDLDefinitions = Field(alias="cddlDefinitions")
+ content_types: ContentTypes = Field(alias="contentTypes")
+ copyright: Copyright
+ cose: CoseDefinitions
+ doc_clusters: DocClusters
+ docs: Documents
+ documentation: Documentation
+ encoding_types: EncodingTypes = Field(alias="encodingTypes")
+ metadata: Metadata
+ form_template: FormTemplate = Field(alias="formTemplate")
+
+ _file: str = PrivateAttr(default="Uninitialized")
+
+ model_config = ConfigDict(extra="forbid")
+
+ @classmethod
+ def load(cls, spec_file: str) -> typing.Self:
+ """Initialize the Signed Document Specification."""
+ with Path(spec_file).open("r") as f:
+ raw_json = f.read()
+ doc = cls.model_validate_json(raw_json, strict=True)
+ doc._file = spec_file # noqa: SLF001
+ return doc
+
+ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
+ """Extra setup after we deserialize."""
+ super().model_post_init(context)
+
+ # Put Base Document Types inside the individual doc types for easy reference.
+ self.docs.set_base_types(self.base_types)
+ self.metadata.set_name(None)
+
+ # Build dynamic CDDL Definitions from the defined headers.
+ self.cddl_definitions.add(
+ [
+ Metadata.custom_metadata_header(
+ self.cddl_definitions.get("Signed_Document_Metadata_Headers"),
+ self.metadata.headers.all,
+ self.metadata.formats,
+ ),
+ Metadata.custom_metadata_header(
+ self.cddl_definitions.get("COSE_Document_Standard_Headers"),
+ self.cose.headers.all,
+ self.cose.header_formats,
+ ),
+ Metadata.custom_metadata_header(
+ self.cddl_definitions.get("COSE_Signature_Standard_Headers"),
+ self.cose.signature_headers.all,
+ self.cose.header_formats,
+ ),
+ ]
+ )
+
+ def get_copyright(
+ self,
+ document_name: str | None,
+ ) -> tuple[Authors, Copyright, list[ChangeLogEntry], datetime.date]:
+ """Get copyright information from the spec."""
+
+ def get_latest_file_change(
+ versions: list[ChangeLogEntry], doc_versions: list[ChangeLogEntry] | None
+ ) -> datetime.date:
+ """Get the largest document version date."""
+ latest_date = datetime.date.fromtimestamp(0.0) # noqa: DTZ012
+ for ver in versions:
+ latest_date = max(latest_date, ver.modified)
+
+ if doc_versions is not None:
+ for ver in doc_versions:
+ latest_date = max(latest_date, ver.modified)
+
+ return latest_date
+
+ authors = self.authors
+ copyright_data = self.copyright
+ versions = copyright_data.versions
+
+ doc_versions = None
+ if document_name is not None:
+ doc = self.docs.get(document_name)
+ authors = doc.authors.combine(authors)
+ doc_versions = doc.versions
+
+ latest_change = get_latest_file_change(versions, doc_versions)
+ if doc_versions is not None:
+ versions = doc_versions
+
+ return (authors, copyright_data, versions, latest_change)
+
+ def get_metadata(self, metadata_name: str, doc_name: str | None = None) -> MetadataHeader:
+ """Get a metadata definition by name, and optionally for a document."""
+ if doc_name is None:
+ raw_metadata_def = self.metadata.headers.get(metadata_name)
+ else:
+ raw_metadata_def = self.docs.get(doc_name).metadata.get(metadata_name)
+ raw_metadata_def.set_name(metadata_name, doc_name)
+ return raw_metadata_def
+
+ def get_metadata_as_markdown(self, doc_name: str | None = None) -> str:
+ """Get metadata definitions in a markdown format."""
+ fields = self.metadata.headers.names
+ field_display = ""
+ for field in fields:
+ doc_types = None
+ if doc_name is not None:
+ doc_types = self.docs.type(doc_name)
+ metadata_def = self.get_metadata(field, doc_name)
+ if doc_name is None or metadata_def.required != OptionalField.excluded:
+ field_display += metadata_def.metadata_as_markdown(
+ doc_types=doc_types,
+ )
+ return field_display.strip()
diff --git a/specs/gen_docs/spec/signers.py b/specs/generators/packages/spec/src/spec/signers.py
similarity index 96%
rename from specs/gen_docs/spec/signers.py
rename to specs/generators/packages/spec/src/spec/signers.py
index e594d589ab..475984fb96 100644
--- a/specs/gen_docs/spec/signers.py
+++ b/specs/generators/packages/spec/src/spec/signers.py
@@ -27,6 +27,6 @@ class Signers(BaseModel):
roles: AllowedRoles
referenced: bool = Field(default=False)
- update: AllowedUpdaters
+ update: dict[str, bool]
model_config = ConfigDict(extra="forbid")
diff --git a/specs/generators/pyproject.toml b/specs/generators/pyproject.toml
new file mode 100644
index 0000000000..2d3ee18492
--- /dev/null
+++ b/specs/generators/pyproject.toml
@@ -0,0 +1,42 @@
+[project]
+name = "generators"
+version = "0.1.0"
+requires-python = ">=3.13"
+dependencies = [
+ "jsonschema[format]>=4.24.0",
+ "mdformat>=0.7.22",
+ "mdformat-mkdocs>=4.3.0",
+ "pydantic>=2.11.7",
+ "pydot>=4.0.1",
+ "rich>=14.0.0",
+ "rich-argparse>=1.7.1",
+ "spec",
+]
+
+[project.scripts]
+validator = "validator.main:main"
+docs = "docs.main:main"
+
+[tool.uv.workspace]
+members = [
+ "packages/spec",
+]
+
+[tool.uv.sources]
+spec = { workspace = true }
+
+[tool.ruff]
+# Extend the project wide `ruff.toml` file.
+# Done so we can add known libraries to sorting.
+extend = "../../ruff.toml"
+
+[tool.ruff.lint.isort]
+#known-third-party = ["pydantic", "pydot", "rich", "rich-argparse"]
+known-first-party = ["spec"]
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/validator", "packages/spec"]
diff --git a/specs/gen_docs/gen/__init__.py b/specs/generators/src/docs/__init__.py
similarity index 100%
rename from specs/gen_docs/gen/__init__.py
rename to specs/generators/src/docs/__init__.py
index c41bcac355..276224dced 100644
--- a/specs/gen_docs/gen/__init__.py
+++ b/specs/generators/src/docs/__init__.py
@@ -1,2 +1,2 @@
-# Intentionally Empty
"""Doc Generator Module."""
+# Intentionally Empty
diff --git a/specs/generators/src/docs/cddl_file.py b/specs/generators/src/docs/cddl_file.py
new file mode 100644
index 0000000000..fb4517542f
--- /dev/null
+++ b/specs/generators/src/docs/cddl_file.py
@@ -0,0 +1,46 @@
+"""Generate CDDL Files."""
+
+import argparse
+import textwrap
+
+from spec.signed_doc import SignedDoc
+
+from .doc_generator import DocGenerator
+
+
+class CDDLFile(DocGenerator):
+ """Generate a CDDL File."""
+
+ def __init__(self, args: argparse.Namespace, spec: SignedDoc, cddl_root: str) -> None:
+ """CDDL File Generator."""
+ file_name = "cddl/" + cddl_root.lower().replace(" ", "_").replace("-", "_") + ".cddl"
+
+ super().__init__(args, spec, file_name, flags=self.NO_FLAGS)
+ self._cddl_root = cddl_root
+
+ def markdown_reference(self, *, indent: int = 0, relative_doc: DocGenerator | None = None) -> str:
+ """Create a Markdown formatted reference for the CDDL file."""
+ file_path = self.file_path(relative_doc)
+ file_name = self.file_name()
+
+ return textwrap.indent(
+ f"""
+
+??? note "CDDL Specification"
+
+ * [{file_name}]({file_path})
+
+ ```cddl
+ {{{{ include_file('./{file_path}', indent={indent + 4}) }}}}
+ ```
+
+
+""".strip(),
+ " " * indent,
+ )
+
+ def generate(self) -> bool:
+ """Generate a CDDL File."""
+ self._filedata = self._spec.cddl_definitions.cddl_file(self._cddl_root)
+
+ return super().generate()
diff --git a/specs/gen_docs/gen/doc_generator.py b/specs/generators/src/docs/doc_generator.py
similarity index 85%
rename from specs/gen_docs/gen/doc_generator.py
rename to specs/generators/src/docs/doc_generator.py
index f392378355..8fc062d1c7 100644
--- a/specs/gen_docs/gen/doc_generator.py
+++ b/specs/generators/src/docs/doc_generator.py
@@ -11,8 +11,8 @@
import rich
import rich.markdown
-from spec.metadata import Metadata
-from spec.signed_doc import HeaderType, SignedDoc
+from docs.markdown import MarkdownHelpers
+from spec.signed_doc import SignedDoc
class DocGenerator:
@@ -45,11 +45,6 @@ def __init__(
# Make sure any destination directory exists.
self._filepath.parent.mkdir(parents=True, exist_ok=True)
- @staticmethod
- def uuid_as_cbor(uuid: str) -> str:
- """UUID in CBOR Diagnostic Notation."""
- return f"37(h'{uuid.replace('-', '')}')"
-
@staticmethod
def name_to_spec_link(name: str, ref: str | None = None) -> str:
"""Create a link to a document type, and an optional ref inside the document."""
@@ -93,8 +88,8 @@ def add_doc_ref_links(self, *, primary_source: bool = False) -> None:
All Document References in text must be as `` or they will not be linked.
"""
self.add_generic_markdown_links(
- self._spec.document_names(),
- Metadata.doc_ref_link,
+ self._spec.docs.names,
+ MarkdownHelpers.doc_ref_link,
primary_source=primary_source,
)
@@ -103,10 +98,9 @@ def add_metadata_links(self) -> None:
All metadata fields in text must be as `` or they will not be linked.
"""
- _, metadata_names, _ = self._spec.headers_and_order(header_type=HeaderType.METADATA)
self.add_generic_markdown_links(
- metadata_names,
- Metadata.field_link,
+ self._spec.metadata.headers.names,
+ MarkdownHelpers.field_link,
primary_source=self._is_metadata_primary_source,
)
@@ -116,8 +110,8 @@ def add_metadata_format_links(self) -> None:
All metadata formats in text must be as `` or they will not be linked.
"""
self.add_generic_markdown_links(
- self._spec.format_names(header_type=HeaderType.METADATA),
- Metadata.format_link,
+ self._spec.metadata.formats.all,
+ MarkdownHelpers.format_link,
primary_source=self._is_metadata_primary_source,
)
@@ -168,13 +162,11 @@ def add_reference_links(self) -> None:
self.strip_end_whitespace()
- actual_link_names = self._spec.link_names()
-
- actual_links_used = {}
- for link_name in actual_link_names:
+ actual_links_used: dict[str, str] = {}
+ for link_name in self._spec.documentation.links.all:
esc_link_name = re.escape(link_name)
link_name_regex = f"(^|\\s)({esc_link_name})(\\.|\\s|$)"
- aka = self._spec.link_name_aka(link_name)
+ aka = self._spec.documentation.links.aka(link_name)
if aka is not None:
replacement = f"\\1[\\2][{aka}]\\3"
link_name = aka # noqa: PLW2901
@@ -185,17 +177,17 @@ def add_reference_links(self) -> None:
link_name_regex,
replacement,
):
- actual_links_used[link_name] = self._spec.link_for_link_name(link_name)
+ actual_links_used[link_name] = self._spec.documentation.links.link(link_name)
for link, actual in actual_links_used.items():
self._filedata += f"\n[{link}]: {actual}"
- def remove_tabs(self, tabstop: int = 4) -> str:
+ def remove_tabs(self, tabstop: int = 4) -> None:
"""Replace tabs in the input text with spaces so that the text aligns on tab stops.
Args:
text (str): The input text containing tabs.
- tabstop (int): The number of characters per tab stop. Default is 8.
+ tabstop (int): The number of characters per tab stop. Default is 4.
Returns:
str: Text with tabs replaced by spaces, aligned at each tab stop.
@@ -210,9 +202,15 @@ def replace_tab(match: re.Match[str]) -> str:
return " " * (tabstop - (position % tabstop))
# Substitute tabs with spaces, using a custom replacement function
- no_tabs_text = re.sub(pattern, replace_tab, self._filedata)
+ lines = list[str](
+ self._filedata.splitlines() # type: ignore # noqa: PGH003
+ )
+ no_tabs: list[str] = []
+ for line in lines:
+ new_line = re.sub(pattern, replace_tab, line)
+ no_tabs.append(new_line)
- self._filedata = no_tabs_text
+ self._filedata = "\n".join(no_tabs)
def insert_copyright(self, *, changelog: bool = True) -> str:
"""Generate a copyright notice into the given document data.
@@ -242,8 +240,8 @@ def insert_copyright(self, *, changelog: bool = True) -> str:
)
author_title = " Authors "
- for author in sorted(authors):
- copyright_notice += f"|{author_title}| {author} <{authors[author]}> |\n"
+ for author in authors.all():
+ copyright_notice += f"|{author_title}| {author} <{authors.email(author)}> |\n"
author_title = " "
if changelog:
@@ -276,6 +274,20 @@ def generate(self) -> bool:
# Remove any leading or trailing newlines and add a single newline at the end/
# Helps make clean markdown files.
+ # if self.file_name().endswith(".md"):
+ # because mdformat turns `*` list markers into `-` and it can't be configured
+ # tell mdlint that in these files it should be "consistent" which will allow
+ # the formatted markdown to pass lints.
+ # self._filedata = f"""
+ #
+ # {self._filedata}"""
+ # self._filedata = mdformat.text( # type: ignore # noqa: PGH003
+ # self._filedata, options={"number": True, "wrap": "keep"}, extensions=["mkdocs"]
+ # ) # noqa: ERA001, RUF100
+ # else: # noqa: ERA001
self.strip_end_whitespace()
return True
@@ -343,7 +355,7 @@ def file_name(self) -> str:
"""Return the files name."""
return self._filename
- def file_path(self, relative_doc: typing.Self | None = None) -> Path:
+ def file_path(self, relative_doc: "DocGenerator | None" = None) -> Path:
"""Return a path to the file."""
if relative_doc is not None:
relative_path = relative_doc.file_path().parent
diff --git a/specs/gen_docs/gen/doc_relationship_diagrams.py b/specs/generators/src/docs/doc_relationship_diagrams.py
similarity index 80%
rename from specs/gen_docs/gen/doc_relationship_diagrams.py
rename to specs/generators/src/docs/doc_relationship_diagrams.py
index b7a0d68b2b..d61c3033e2 100644
--- a/specs/gen_docs/gen/doc_relationship_diagrams.py
+++ b/specs/generators/src/docs/doc_relationship_diagrams.py
@@ -3,11 +3,12 @@
import argparse
import textwrap
-from gen.doc_generator import DocGenerator
-from gen.graphviz_doc_diagram import Cluster, DotFile, DotLink, DotLinkEnd, DotSignedDoc, FontTheme, TableRow
-from spec.metadata import Metadata
+from docs.markdown import MarkdownHelpers
from spec.optional import OptionalField
-from spec.signed_doc import HeaderType, SignedDoc
+from spec.signed_doc import SignedDoc
+
+from .doc_generator import DocGenerator
+from .graphviz_doc_diagram import Cluster, DotFile, DotLink, DotLinkEnd, DotSignedDoc, FontTheme, TableRow
class DocRelationshipFile(DocGenerator):
@@ -45,31 +46,33 @@ def markdown_reference(
def generate(self) -> bool: # noqa: C901
"""Generate a Document Relationship Diagram File."""
- doc_names = self._spec.document_names() if self._document_name is None else [self._document_name]
+ doc_names = self._spec.docs.names if self._document_name is None else [self._document_name]
file_id = self._document_name if self._document_name is not None else "All"
file_title = textwrap.fill(f"{file_id} Document Relationships", width=30)
dot_file = DotFile(
- self._document_name, file_title, depth=self._depth, title_size=150 if self._document_name is None else 50
+ file_id, file_title, depth=self._depth, title_size=150 if self._document_name is None else 50
)
all_dst_refs: list[str] = []
for doc in doc_names:
- cluster = Cluster.from_doc_cluster(self._spec.doc_in_cluster(doc))
+ cluster = Cluster.from_doc_cluster(self._spec.doc_clusters.get(doc))
doc_table = DotSignedDoc(
table_id=doc,
- title_href=Metadata.doc_ref_link(doc, self._depth, html=True),
+ title_href=MarkdownHelpers.doc_ref_link(doc, self._depth, html=True),
cluster=cluster,
)
- doc_data = self._spec.get_document(doc)
+ doc_data = self._spec.docs.get(doc)
+ doc_type = doc_data.type.formatted_ids(prefix="", separator=" ", suffix="", cbor=False)
- # Add content type explicitely to table.
- doc_table.add_row(TableRow(name="content type", value=doc_data.headers["content type"].value))
+ if doc_data.headers is not None:
+ # Add content type explicitely to table.
+ doc_table.add_row(TableRow(name="content type", value=doc_data.content_type))
# Add all used Metadata to table.
- for meta in self._spec.all_headers(HeaderType.METADATA):
+ for meta in self._spec.metadata.headers.names:
doc_metadata = self._spec.get_metadata(meta, doc)
# Skip excluded metadata.
if doc_metadata.required == OptionalField.excluded:
@@ -79,7 +82,7 @@ def generate(self) -> bool: # noqa: C901
doc_table.add_row(
TableRow(
name=meta,
- value=doc_data.type,
+ value=doc_type,
value_theme=FontTheme(face="Courier", bold=True, italic=True),
)
)
@@ -95,10 +98,10 @@ def generate(self) -> bool: # noqa: C901
dst_dir = "n" if doc == link_dst else "w"
# Add dummy destination table, in case we don't have it in our docs.
- ref_cluster = Cluster.from_doc_cluster(self._spec.doc_in_cluster(link_dst))
+ ref_cluster = Cluster.from_doc_cluster(self._spec.doc_clusters.get(link_dst))
dummy_table = DotSignedDoc(
table_id=link_dst,
- title_href=Metadata.doc_ref_link(
+ title_href=MarkdownHelpers.doc_ref_link(
link_dst,
depth=self._depth,
html=True,
@@ -131,10 +134,10 @@ def generate(self) -> bool: # noqa: C901
for ref_doc in doc_data.all_docs_referencing:
if ref_doc not in doc_names:
# Then we need to create a dummy doc and link.
- ref_cluster = Cluster.from_doc_cluster(self._spec.doc_in_cluster(ref_doc))
+ ref_cluster = Cluster.from_doc_cluster(self._spec.doc_clusters.get(ref_doc))
ref_doc_table = DotSignedDoc(
table_id=ref_doc,
- title_href=Metadata.doc_ref_link(ref_doc, self._depth, html=True),
+ title_href=MarkdownHelpers.doc_ref_link(ref_doc, self._depth, html=True),
cluster=ref_cluster,
)
dot_file.add_table(ref_doc_table)
diff --git a/specs/gen_docs/gen/docs_page_md.py b/specs/generators/src/docs/docs_page_md.py
similarity index 69%
rename from specs/gen_docs/gen/docs_page_md.py
rename to specs/generators/src/docs/docs_page_md.py
index 970f2d4836..7d34640b5e 100644
--- a/specs/gen_docs/gen/docs_page_md.py
+++ b/specs/generators/src/docs/docs_page_md.py
@@ -1,15 +1,13 @@
"""Generate the individual pages docs/.md file."""
import argparse
-import json
import typing
-from pydantic import HttpUrl
-
-from gen.doc_generator import DocGenerator
-from gen.doc_relationship_diagrams import DocRelationshipFile
from spec.signed_doc import SignedDoc
+from .doc_generator import DocGenerator
+from .doc_relationship_diagrams import DocRelationshipFile
+
class IndividualDocMd(DocGenerator):
"""Generate the individual pages docs/.md file."""
@@ -27,14 +25,14 @@ def __init__(self, args: argparse.Namespace, spec: SignedDoc, doc_name: str) ->
super().__init__(args, spec, file_name, flags=self.HAS_MARKDOWN_LINKS)
self._document_name = doc_name
- self._doc = self._spec.get_document(doc_name)
+ self._doc = self._spec.docs.get(doc_name)
self._depth = 1
@classmethod
def save_or_validate_all(cls, args: argparse.Namespace, spec: SignedDoc) -> bool:
"""Save or Validate all documentation pages."""
good = True
- for doc_name in spec.document_names():
+ for doc_name in spec.docs.names:
good &= cls(args, spec, doc_name).save_or_validate()
return good
@@ -48,11 +46,15 @@ def description_or_todo(self, desc: str | None) -> str:
def header_parameter_summary(self) -> str:
"""Generate concrete Cose header parameter settings for a specific document."""
headers = self._doc.headers
+
+ if headers is None:
+ return "No Headers are defined for this document."
+
header_docs = ""
- for header, value in headers.items():
- value = value.value # noqa: PLW2901
+ for header in headers.names:
+ value = headers.get(header).value
if isinstance(value, list):
- value = f"[{','.join(value)}]" # noqa: PLW2901
+ value = f"[{','.join(value)}]"
link = f"../spec.md#{header.replace(' ', '-')}"
header_docs += f"* [{header}]({link}) = `{value}`\n"
return header_docs.strip()
@@ -62,42 +64,28 @@ def document_payload(self) -> str:
if self._doc.payload is None:
return self.TODO_MSG
- payload_docs = self._doc.payload.description + "\n"
-
- schema = self._doc.payload.doc_schema
- if schema is not None:
- if isinstance(schema, HttpUrl):
- if schema == "https://json-schema.org/draft-07/schema":
- payload_docs += "\n**Must be a valid JSON Schema Draft 7 document.**"
- else:
- payload_docs += f"\nMust be a valid according to <{schema}>."
- else:
- payload_docs += f"""\nSchema :
-
-```json
-{json.dumps(schema, indent=2, sort_keys=True)}
-```
-
-"""
- return payload_docs.strip()
+ return f"{self._doc.payload}"
def document_signers(self) -> str:
"""Generate documentation about who may sign this documents."""
- signers = self._spec.data()["docs"][self._document_name]["signers"]
- signers_doc = ""
+ signers = self._spec.docs.get(self._document_name).signers
+ signers_doc: str = ""
- for role_group in signers["roles"]:
- roles = signers["roles"][role_group]
- if roles:
- signers_doc += f"\nThe following {role_group} roles may sign documents of this type:\n\n"
+ def add_role_group(name: str, roles: list[str]) -> None:
+ nonlocal signers_doc
+ if len(roles) > 0:
+ signers_doc += f"\nThe following {name} roles may sign documents of this type:\n\n"
for role in roles:
signers_doc += f"* {role}\n"
+ add_role_group("User", signers.roles.user)
+ add_role_group("Admin", signers.roles.admin)
+
signers_doc = signers_doc.strip()
signers_doc += "\n\nNew versions of this document may be published by:\n\n"
- for updater in signers["update"]:
- if signers["update"][updater]:
+ for updater in signers.update:
+ if signers.update[updater]:
signers_doc += f"* {updater}\n"
return signers_doc.strip()
diff --git a/specs/gen_docs/gen/graphviz_doc_diagram.py b/specs/generators/src/docs/graphviz_doc_diagram.py
similarity index 93%
rename from specs/gen_docs/gen/graphviz_doc_diagram.py
rename to specs/generators/src/docs/graphviz_doc_diagram.py
index 3c2ec65b70..2c1d78ce06 100644
--- a/specs/gen_docs/gen/graphviz_doc_diagram.py
+++ b/specs/generators/src/docs/graphviz_doc_diagram.py
@@ -71,6 +71,11 @@ class TableRow(BaseModel):
model_config = ConfigDict(extra="forbid")
+ @classmethod
+ def default_list(cls) -> list["TableRow"]:
+ """Return a default list of this class."""
+ return []
+
def generate(self, bgcolor: str) -> str:
"""Generate a single row of the table."""
value = self.value
@@ -171,6 +176,7 @@ def from_doc_cluster(cls, cluster: DocCluster | None) -> "Cluster | None":
return None
return cls(name=cluster.name)
+ @property
def label(self) -> str:
"""Transform the name into a label."""
return "cluster_" + self.name.lower().replace(" ", "_").replace("-", "_")
@@ -178,7 +184,7 @@ def label(self) -> str:
def start(self) -> str:
"""Start a new cluster."""
return f"""
-subgraph {self.label()} {{
+subgraph {self.label} {{
label = "{self.name}";
color=blue
penwidth=20
@@ -188,7 +194,7 @@ def end(self) -> str:
"""End the cluster."""
return "}\n"
- def __eq__(self, other: "Cluster") -> bool:
+ def __eq__(self, other: object) -> bool:
"""Eq."""
if not isinstance(other, Cluster):
# don't attempt to compare against unrelated types
@@ -203,7 +209,7 @@ class DotSignedDoc(BaseModel):
title_port: str = Field(default="title")
title_href: str | None = Field(default=None)
theme: TableTheme = Field(default_factory=TableTheme)
- rows: list[TableRow] = Field(default_factory=list)
+ rows: list[TableRow] = Field(default_factory=TableRow.default_list)
cluster: Cluster | None = Field(default=None)
model_config = ConfigDict(extra="forbid")
@@ -296,6 +302,11 @@ def is_cluster(self) -> bool:
"""Is the link to a cluster."""
return isinstance(self.port, Cluster)
+ @property
+ def port_label(self) -> str | None:
+ """Get label of the port."""
+ return self.port.label if self.is_cluster else None # type: ignore # noqa: PGH003
+
def __str__(self) -> str:
"""Str."""
name = f'"{self.id}"'
@@ -305,7 +316,7 @@ def __str__(self) -> str:
name += f":{self.dir}"
return name
- def __eq__(self, other: "DotLinkEnd") -> bool:
+ def __eq__(self, other: object) -> bool:
"""Eq."""
if not isinstance(other, DotLinkEnd):
# don't attempt to compare against unrelated types
@@ -335,12 +346,10 @@ def model_post_init(self, context: typing.Any) -> None: # noqa: ANN401
super().model_post_init(context)
# Add cluster parameters to the theme.
- if self.src.is_cluster:
- self.theme.ltail = self.src.port.label()
- if self.dst.is_cluster:
- self.theme.lhead = self.dst.port.label()
+ self.theme.ltail = self.src.port_label
+ self.theme.lhead = self.dst.port_label
- def __eq__(self, other: "DotLink") -> bool:
+ def __eq__(self, other: object) -> bool:
"""Eq."""
if not isinstance(other, DotLink):
# don't attempt to compare against unrelated types
@@ -367,20 +376,20 @@ def __init__(self, file_id: str, title: str, depth: int = 0, title_size: int = 1
self.title = title
self.title_size = title_size
self.rankdir = "LR"
- self.graph = {
+ self.graph: dict[str, str | int] = {
"fontname": DEFAULT_FONT_NAME,
"fontsize": DEFAULT_FONT_SIZE,
"fontcolor": DEFAULT_FONT_COLOR,
"bgcolor": "white",
}
- self.node = {
+ self.node: dict[str, str | int] = {
"penwidth": 0,
"margin": 0,
"fontname": DEFAULT_FONT_NAME,
"fontsize": DEFAULT_FONT_SIZE,
"fontcolor": DEFAULT_FONT_COLOR,
}
- self.edge = {
+ self.edge: dict[str, str | int] = {
"fontname": DEFAULT_FONT_NAME,
"fontsize": DEFAULT_FONT_SIZE,
"fontcolor": "red",
@@ -401,7 +410,7 @@ def add_table(self, table: DotSignedDoc) -> None:
cluster_name = None
if table.cluster is not None:
cluster_name = table.cluster.name
- if cluster_name is not None and cluster_name not in self.clusters:
+ if cluster_name is not None and cluster_name not in self.clusters and table.cluster is not None:
self.clusters[cluster_name] = table.cluster
if cluster_name not in self.tables:
self.tables[cluster_name] = {}
@@ -438,9 +447,9 @@ def clustered_tables(self) -> str:
def __str__(self) -> str:
"""Generate the DOT file."""
- def defaults(name: str, settings: dict) -> str:
+ def defaults(name: str, settings: dict[str, str | int]) -> str:
"""Expand the defaults."""
- defaults = []
+ defaults: list[str] = []
for default, value in settings.items():
defaults.append(f'{default}="{value}"')
return f"{name} [{', '.join(defaults)}];"
diff --git a/specs/gen_docs/main.py b/specs/generators/src/docs/main.py
similarity index 88%
rename from specs/gen_docs/main.py
rename to specs/generators/src/docs/main.py
index 521f49338f..d71b3baa89 100755
--- a/specs/gen_docs/main.py
+++ b/specs/generators/src/docs/main.py
@@ -8,13 +8,15 @@
import rich
from rich_argparse import RichHelpFormatter
-from gen.docs_page_md import IndividualDocMd
-from gen.metadata_md import MetadataMd
-from gen.spec_index import SpecIndex
-from gen.spec_md import SpecMd
-from gen.types_md import TypesMd
from spec.signed_doc import SignedDoc
+from .docs_page_md import IndividualDocMd
+from .metadata_md import MetadataMd
+from .spec_index import SpecIndex
+from .spec_md import SpecMd
+from .templates_md import TemplatesMd
+from .types_md import TypesMd
+
def check_is_dir(base_path: Path) -> bool:
"""Check if the path exists, and is a directory.
@@ -62,8 +64,10 @@ def parse_args() -> argparse.Namespace:
return args
-def main(args: argparse.Namespace) -> None:
+def main() -> None:
"""Generate Signed Document Specification documentation."""
+ args = parse_args()
+
# Get the compiled documentation json file
spec = SignedDoc.load(args.spec)
@@ -76,6 +80,7 @@ def main(args: argparse.Namespace) -> None:
good &= TypesMd(args, spec).save_or_validate()
good &= MetadataMd(args, spec).save_or_validate()
good &= IndividualDocMd.save_or_validate_all(args, spec)
+ good &= TemplatesMd(args, spec).save_or_validate()
if not good:
rich.print("File Comparisons Failed, Documentation is not current.")
@@ -88,4 +93,4 @@ def main(args: argparse.Namespace) -> None:
if __name__ == "__main__":
- main(parse_args())
+ main()
diff --git a/specs/generators/src/docs/markdown.py b/specs/generators/src/docs/markdown.py
new file mode 100644
index 0000000000..4f098d79da
--- /dev/null
+++ b/specs/generators/src/docs/markdown.py
@@ -0,0 +1,46 @@
+"""Markdown Helper and Formatting Functions."""
+
+
+class MarkdownHelpers:
+ """Markdown Helper and Formatting Functions."""
+
+ @staticmethod
+ def format_link(name: str, depth: int = 0, *, file: str = "metadata.md", monospace: bool = False) -> str:
+ """Format link."""
+ link = f"{file}#{name.lower().replace(' ', '-')}"
+
+ while depth > 0:
+ link = f"../{link}"
+ depth -= 1
+
+ if monospace:
+ name = f"`{name}`"
+
+ return f"[{name}]({link})"
+
+ @staticmethod
+ def doc_ref_link(name: str, depth: int = 0, *, html: bool = False) -> str:
+ """Metadata Document Reference link."""
+ link = name.lower().replace(" ", "_")
+
+ if html:
+ link += "/"
+ else:
+ link += ".md"
+
+ if depth == 0:
+ link = f"./docs/{link}"
+ else:
+ maxdepth = 0 if html else 1
+ while depth > maxdepth:
+ link = f"../{link}"
+ depth -= 1
+
+ if html:
+ return link
+ return f"[{name}]({link})"
+
+ @staticmethod
+ def field_link(name: str, depth: int = 0) -> str:
+ """Metadata Field link."""
+ return MarkdownHelpers.format_link(name, depth, monospace=True)
diff --git a/specs/gen_docs/gen/metadata_md.py b/specs/generators/src/docs/metadata_md.py
similarity index 67%
rename from specs/gen_docs/gen/metadata_md.py
rename to specs/generators/src/docs/metadata_md.py
index 38bce8a448..4256b315a5 100644
--- a/specs/gen_docs/gen/metadata_md.py
+++ b/specs/generators/src/docs/metadata_md.py
@@ -5,10 +5,11 @@
import rich
from rich.console import Console
-from gen.cddl_file import CDDLFile
-from gen.doc_generator import DocGenerator
from spec.signed_doc import SignedDoc
+from .cddl_file import CDDLFile
+from .doc_generator import DocGenerator
+
console = Console()
@@ -28,8 +29,8 @@ def metadata_types(self) -> str:
"""Generate the metadata types documentation."""
metadata_types = ""
- for format_name in self._spec.get_all_metadata_formats():
- format_def = self._spec.get_metadata_format(format_name)
+ for format_name in self._spec.metadata.formats.all:
+ format_def = self._spec.metadata.formats.get(format_name)
cddl_def = CDDLFile(self._args, self._spec, format_def.cddl)
if not cddl_def.save_or_validate():
@@ -69,25 +70,3 @@ def generate(self) -> bool:
console.print_exception()
return False
return super().generate()
-
- @staticmethod
- def format_link(name: str, depth: int = 0) -> str:
- """Metadata Format link."""
- link = f"metadata.md#{name.lower().replace(' ', '-')}"
-
- while depth > 0:
- link = f"../{link}"
- depth -= 1
-
- return f"[{name}]({link})"
-
- @staticmethod
- def field_link(name: str, depth: int = 0) -> str:
- """Metadata Field link."""
- link = f"metadata.md#{name.lower().replace('`', '')}"
-
- while depth > 0:
- link = f"../{link}"
- depth -= 1
-
- return f"[`{name}`]({link})"
diff --git a/specs/gen_docs/gen/spec_index.py b/specs/generators/src/docs/spec_index.py
similarity index 88%
rename from specs/gen_docs/gen/spec_index.py
rename to specs/generators/src/docs/spec_index.py
index 56da19a411..b7c9e893e7 100644
--- a/specs/gen_docs/gen/spec_index.py
+++ b/specs/generators/src/docs/spec_index.py
@@ -2,9 +2,10 @@
import argparse
-from gen.doc_generator import DocGenerator
from spec.signed_doc import SignedDoc
+from .doc_generator import DocGenerator
+
class SpecIndex(DocGenerator):
"""Spec Index Generator."""
@@ -21,6 +22,7 @@ def generate(self) -> bool:
- Specification: spec.md
- Metadata Fields: metadata.md
- Document Types: types.md
+ - Document Templates: templates.md
- docs
"""
return super().generate()
diff --git a/specs/gen_docs/gen/spec_md.py b/specs/generators/src/docs/spec_md.py
similarity index 55%
rename from specs/gen_docs/gen/spec_md.py
rename to specs/generators/src/docs/spec_md.py
index bd8638c8db..0d4f57a1c1 100644
--- a/specs/gen_docs/gen/spec_md.py
+++ b/specs/generators/src/docs/spec_md.py
@@ -2,9 +2,11 @@
import argparse
-from gen.cddl_file import CDDLFile
-from gen.doc_generator import DocGenerator
-from spec.signed_doc import HeaderType, SignedDoc
+from spec.cddl.cose import CoseHeader, HeaderType
+from spec.signed_doc import SignedDoc
+
+from .cddl_file import CDDLFile
+from .doc_generator import DocGenerator
class SpecMd(DocGenerator):
@@ -14,48 +16,50 @@ def __init__(self, args: argparse.Namespace, spec: SignedDoc) -> None:
"""Initialise Spec.md generator."""
super().__init__(args, spec, "spec.md")
- def header_parameter_doc(self, header: str, header_type: HeaderType) -> str:
+ def header_parameter_doc(self, header: CoseHeader) -> str:
"""Create documentation for a single cose header."""
- options = self._spec.header(header, header_type=header_type)
- label = options.get("coseLabel")
-
custom_header = "***Custom Header***"
- if not isinstance(label, str):
+ if not isinstance(header.cose_label, str):
custom_header = ""
- header_format = options["format"]
- header_value = options.get("value", None)
- header_format_display = f"{header_format}"
- if isinstance(header_value, list) and len(header_value) > 0:
+
+ header_format_display = f"{header.format}"
+ if isinstance(header.value, list) and len(header.value) > 0:
header_format_display += "\n * Supported Values:"
- for value in header_value:
+ for value in header.value:
value_entry = f"\n * {value}"
description = None
- if header_format == "Media Type":
- description = self._spec.content_type_description(value)
- if header_format == "HTTP Content Encoding":
- description = self._spec.encoding_type_description(value)
+ if header.format == "Media Type":
+ description = self._spec.content_types.description(value)
+ if header.format == "HTTP Content Encoding":
+ description = self._spec.encoding_types.description(value)
if description is not None:
- value_entry += f" : {description.replace('\n', '\n ')}"
+ value_entry += f" : {f'\n{description}'.replace('\n', '\n ')}"
header_format_display += value_entry
return f"""
-#### `{header}`
+#### `{header.name()}`
-{options.get("description")}
+{header.description}
-* Required : {options["required"]}
-* Cose Label : {label} {custom_header}
+* Required : {header.required.value}
+* Cose Label : {header.cose_label} {custom_header}
* Format : {header_format_display}
"""
def cose_header_parameters(self, header_type: HeaderType) -> str:
"""Insert details about Cose header Parameters that are defined for use."""
- headers = self._spec.all_headers(header_type)
+ if header_type == HeaderType.DOCUMENT:
+ headers = self._spec.cose.headers.all
+ elif header_type == HeaderType.SIGNATURE:
+ headers = self._spec.cose.signature_headers.all
+ else:
+ return "" # No Cose Headers in metadata.
+
header_parameters_doc = ""
for header in headers:
- header_parameters_doc += self.header_parameter_doc(header, header_type=header_type)
+ header_parameters_doc += self.header_parameter_doc(header)
return header_parameters_doc.strip()
@@ -93,6 +97,40 @@ def generate(self) -> bool:
Specifically, the COSE Sign format is used.
This allows one or more signatures to be attached to the same document.
+While every Catalyst Signed Document is a valid COSE Sign format document,
+not every COSE Sign format document is a valid Catalyst Signed Document.
+The following restrictions apply:
+
+### Unprotected Headers are not permitted
+
+It is a requirement that any document that contains exactly the same data, must produce the same
+catalyst signed document.
+This means that unprotected headers, which do not form part of the data protected by
+the signature are not permitted.
+Any document which contains any unprotected headers is not a valid Catalyst Signed Document,
+even though it may be a valid COSE Sign formatted document.
+
+### Only defined metadata and COSE Headers are allowed
+
+Each document type, defines a set of metadata and the COSE Headers which are allowed in that document type.
+Even if the Catalyst Signed document metadata exists in this specification, IF it is not defined as
+a valid metadata or COSE Header field for that particular document it may not be present.
+Unexpected but otherwise valid Metadata or COSE Header fields invalidate the Catalyst Signed Document.
+
+### No undefined metadata or unused COSE Headers may be present
+
+COSE Header Fields which are defined by the COSE Specification, but are NOT defined as part of a
+Catalyst Signed Document may not be present.
+Any such COSE Header Fields present in the document render it an invalid Catalyst Signed Document.
+
+Any metadata field that is not defined in this specification may not be present in any protected header.
+Unrecognized metadata fields in a document render it an invalid Catalyst Signed Document.
+
+### CBOR Deterministic Encoding MUST be used
+
+The Catalyst Signed Document **MUST** be encoded using CBOR Deterministic Encoding.
+The "length-first core deterministic encoding requirements" variant of deterministic encoding *MUST* be used.
+
### Signed Document CDDL Definition
{signed_doc_cddl.markdown_reference(relative_doc=self)}
@@ -119,8 +157,7 @@ def generate(self) -> bool:
### Metadata
-Catalyst Signed Documents extend the Header Parameters with a series of Metadata fields.
-These fields are defined [here](./metadata.md).
+Catalyst Signed Documents extend the Header Parameters with a series of [Metadata fields](./metadata.md).
### Signing Catalyst Signed Documents
diff --git a/specs/generators/src/docs/template_example_schema_json.py b/specs/generators/src/docs/template_example_schema_json.py
new file mode 100644
index 0000000000..d85cf46a17
--- /dev/null
+++ b/specs/generators/src/docs/template_example_schema_json.py
@@ -0,0 +1,41 @@
+"""Generate the template_example.schema.json file."""
+
+import argparse
+import json
+from typing import Any
+
+import jsonschema
+
+from spec.signed_doc import SignedDoc
+
+from .doc_generator import DocGenerator
+
+
+class TemplateExampleSchemaJson(DocGenerator):
+ """Generate the template_example.schema.json file."""
+
+ def __init__(self, args: argparse.Namespace, spec: SignedDoc) -> None:
+ """Initialise template_example.schema.json generator."""
+ file_name = "schema/template_example.schema.json"
+
+ super().__init__(args, spec, file_name)
+
+ def generate(self) -> bool:
+ """Generate a `template_example.schema.json` file from the definitions."""
+ schema: dict[str, Any] = {
+ "$schema": "https://json-schema.org/draft/2020-12/schema#",
+ "title": "Example Template Schema",
+ "description": "Example Template Schema showing all defined field types.",
+ "maintainers": [{"name": "Catalyst Team", "url": "https://projectcatalyst.io/"}],
+ "$defs": self._spec.form_template.json_definition,
+ "type": "object",
+ "additionalProperties": False,
+ "properties": self._spec.form_template.example,
+ }
+
+ template_schema = json.dumps(schema, indent=4)
+ jsonschema.Draft202012Validator.check_schema(schema)
+
+ self._filedata = template_schema
+
+ return super().generate()
diff --git a/specs/generators/src/docs/templates_md.py b/specs/generators/src/docs/templates_md.py
new file mode 100644
index 0000000000..5685a35c2f
--- /dev/null
+++ b/specs/generators/src/docs/templates_md.py
@@ -0,0 +1,29 @@
+"""Generate the templates.md file."""
+
+import argparse
+
+from spec.signed_doc import SignedDoc
+
+from .doc_generator import DocGenerator
+from .template_example_schema_json import TemplateExampleSchemaJson
+
+
+class TemplatesMd(DocGenerator):
+ """Generate the templates.md file."""
+
+ def __init__(self, args: argparse.Namespace, spec: SignedDoc) -> None:
+ """Initialise Spec.md generator."""
+ super().__init__(args, spec, "templates.md")
+
+ def generate(self) -> bool:
+ """Generate a `templates.md` file from the definitions."""
+ # Generate the example_template_schema.json file.
+ example_schema = TemplateExampleSchemaJson(self._args, self._spec)
+ if not example_schema.save_or_validate():
+ return False
+
+ self._filedata = """
+# Templates"
+"""
+
+ return super().generate()
diff --git a/specs/gen_docs/gen/types_md.py b/specs/generators/src/docs/types_md.py
similarity index 59%
rename from specs/gen_docs/gen/types_md.py
rename to specs/generators/src/docs/types_md.py
index 7c7f7da4bf..68b1ab907c 100644
--- a/specs/gen_docs/gen/types_md.py
+++ b/specs/generators/src/docs/types_md.py
@@ -2,10 +2,11 @@
import argparse
-from gen.doc_generator import DocGenerator
-from gen.doc_relationship_diagrams import DocRelationshipFile
from spec.signed_doc import SignedDoc
+from .doc_generator import DocGenerator
+from .doc_relationship_diagrams import DocRelationshipFile
+
class TypesMd(DocGenerator):
"""Generate the `types.md` File."""
@@ -14,51 +15,33 @@ def __init__(self, args: argparse.Namespace, spec: SignedDoc) -> None:
"""Initialize."""
super().__init__(args, spec, "types.md")
- def formatted_doc_types(self, name: str) -> str:
- """Return a formatted doc types entry."""
- types = self._spec.document_type(name)
- type_names = ""
- for sub_type in types:
- type_names += f"{self._spec.doc_name_for_type(sub_type)}/"
- return type_names[:-1]
-
- def formatted_cbor_doc_types(self, name: str) -> str:
- """Return doc types formatted as cbor."""
- types = self._spec.document_type(name)
- type_names = "["
- for sub_type in types:
- type_names += self.uuid_as_cbor(sub_type) + ", "
- return type_names[:-6] + "]"
-
- def doc_type_summary(self) -> None:
+ def doc_type_summary(self) -> str:
"""Generate a Document Base Type Summary from the Document Specifications Data."""
- doc_types = self._spec.base_document_types()
-
doc_type_summary = """
| Base Type | UUID | CBOR |
| :--- | :--- | :--- |
"""
- for k, v in doc_types.items():
- doc_type_summary += f"| {k} | `{v}` | `{self.uuid_as_cbor(v)}` |\n"
+ for type_name in self._spec.base_types.all:
+ uuid = self._spec.base_types.uuid(type_name)
+ doc_type_summary += f"| {type_name} | `{uuid.as_uuid_str}` | `{uuid.as_cbor}` |\n"
return doc_type_summary.strip()
def doc_type_details(self) -> str:
"""Generate a Document Type Detailed Summary from the Document Specifications Data."""
- docs = self._spec.document_names()
-
doc_type_details = """
| Document Type | Base Types | CBOR |
| :--- | :--- | :--- |
"""
- for k in docs:
+ for k in self._spec.docs.names:
+ doc_type = self._spec.docs.type(k)
doc_type_details += (
f"| [{k}]({self.name_to_spec_link(k)}) |"
- f" {self.formatted_doc_types(k)} |"
- f" {self.formatted_cbor_doc_types(k)} |\n"
+ f" {doc_type.formatted_names()} |"
+ f" {doc_type.formatted_ids(separator=', ')} |\n"
)
doc_type_details += ""
diff --git a/specs/generators/src/validator/__init__.py b/specs/generators/src/validator/__init__.py
new file mode 100644
index 0000000000..5182ed05f6
--- /dev/null
+++ b/specs/generators/src/validator/__init__.py
@@ -0,0 +1 @@
+"""Intentionally Blank."""
diff --git a/specs/generators/src/validator/main.py b/specs/generators/src/validator/main.py
new file mode 100644
index 0000000000..51ef671b6c
--- /dev/null
+++ b/specs/generators/src/validator/main.py
@@ -0,0 +1,74 @@
+"""Specification Validator."""
+
+import argparse
+import sys
+
+import rich
+from pydantic import ValidationError
+from rich.table import Table
+from rich_argparse import RichHelpFormatter
+
+from spec.signed_doc import SignedDoc
+
+
+def parse_args() -> argparse.Namespace:
+ """Initialise and run the CLI parser."""
+ parser = argparse.ArgumentParser(
+ description="Project Catalyst - Architectural Specifications Validator",
+ formatter_class=RichHelpFormatter,
+ )
+ parser.add_argument("spec", help="Path to JSON Specification file")
+
+ return parser.parse_args()
+
+
+def main() -> None:
+ """Validate Architectural Specifications."""
+ args = parse_args()
+
+ # Get the compiled documentation json file
+ # Specs are validated automatically on load.
+ try:
+ _spec = SignedDoc.load(args.spec)
+ rich.print("Architectural Specifications Validated Successfully.")
+ except ValidationError as exc:
+ table = Table(
+ title=f"{exc.error_count()} Locations where Schema Data does not match the {exc.title} Model.",
+ caption="Model does not match Schema and needs updating.",
+ )
+ table.add_column("Key", no_wrap=True, style="yellow")
+ table.add_column("Error", no_wrap=True, style="red")
+ table.add_column("Input", no_wrap=True, max_width=30, style="grey37")
+
+ error_links: dict[str, str] = {}
+ errors = exc.errors()
+ errors.sort(key=lambda x: [x["loc"], x["type"]])
+ for error in errors:
+ error_links[error["msg"]] = error["url"] # type: ignore # noqa: PGH003
+
+ loc: list[str] = []
+ for x in error["loc"]:
+ if isinstance(x, int):
+ loc.append(f"[{x}]")
+ else:
+ loc.append(f"{x}")
+
+ table.add_row(
+ ".".join(loc),
+ error["msg"],
+ str(error["input"]).splitlines()[0],
+ )
+ rich.print(table)
+
+ for msg, url in error_links.items():
+ rich.print(f"* {msg} : {url}")
+
+ sys.exit(1)
+
+ except Exception: # noqa: BLE001
+ rich.get_console().print_exception(show_locals=True)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/specs/generators/uv.lock b/specs/generators/uv.lock
new file mode 100644
index 0000000000..f8da6b8557
--- /dev/null
+++ b/specs/generators/uv.lock
@@ -0,0 +1,492 @@
+version = 1
+revision = 2
+requires-python = ">=3.13"
+
+[manifest]
+members = [
+ "generators",
+ "spec",
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "arrow"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "python-dateutil" },
+ { name = "types-python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960, upload-time = "2023-09-30T22:11:18.25Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload-time = "2023-09-30T22:11:16.072Z" },
+]
+
+[[package]]
+name = "attrs"
+version = "25.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
+]
+
+[[package]]
+name = "fqdn"
+version = "1.5.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" },
+]
+
+[[package]]
+name = "generators"
+version = "0.1.0"
+source = { editable = "." }
+dependencies = [
+ { name = "jsonschema", extra = ["format"] },
+ { name = "mdformat" },
+ { name = "mdformat-mkdocs" },
+ { name = "pydantic" },
+ { name = "pydot" },
+ { name = "rich" },
+ { name = "rich-argparse" },
+ { name = "spec" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "jsonschema", extras = ["format"], specifier = ">=4.24.0" },
+ { name = "mdformat", specifier = ">=0.7.22" },
+ { name = "mdformat-mkdocs", specifier = ">=4.3.0" },
+ { name = "pydantic", specifier = ">=2.11.7" },
+ { name = "pydot", specifier = ">=4.0.1" },
+ { name = "rich", specifier = ">=14.0.0" },
+ { name = "rich-argparse", specifier = ">=1.7.1" },
+ { name = "spec", editable = "packages/spec" },
+]
+
+[[package]]
+name = "idna"
+version = "3.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
+]
+
+[[package]]
+name = "isoduration"
+version = "20.11.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "arrow" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" },
+]
+
+[[package]]
+name = "jsonpointer"
+version = "3.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" },
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.24.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480, upload-time = "2025-05-26T18:48:10.459Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709, upload-time = "2025-05-26T18:48:08.417Z" },
+]
+
+[package.optional-dependencies]
+format = [
+ { name = "fqdn" },
+ { name = "idna" },
+ { name = "isoduration" },
+ { name = "jsonpointer" },
+ { name = "rfc3339-validator" },
+ { name = "rfc3987" },
+ { name = "uri-template" },
+ { name = "webcolors" },
+]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "referencing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
+]
+
+[[package]]
+name = "mdformat"
+version = "0.7.22"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fc/eb/b5cbf2484411af039a3d4aeb53a5160fae25dd8c84af6a4243bc2f3fedb3/mdformat-0.7.22.tar.gz", hash = "sha256:eef84fa8f233d3162734683c2a8a6222227a229b9206872e6139658d99acb1ea", size = 34610, upload-time = "2025-01-30T18:00:51.418Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f2/6f/94a7344f6d634fe3563bea8b33bccedee37f2726f7807e9a58440dc91627/mdformat-0.7.22-py3-none-any.whl", hash = "sha256:61122637c9e1d9be1329054f3fa216559f0d1f722b7919b060a8c2a4ae1850e5", size = 34447, upload-time = "2025-01-30T18:00:48.708Z" },
+]
+
+[[package]]
+name = "mdformat-gfm"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "mdformat" },
+ { name = "mdformat-tables" },
+ { name = "mdit-py-plugins" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e5/db/873bad63b36e390a33bc0cf7222442010997d3ccf29a1889f24d28fdeddd/mdformat_gfm-0.4.1.tar.gz", hash = "sha256:e189e728e50cfb15746abc6b3178ca0e2bebbb7a8d3d98fbc9e24bc1a4c65564", size = 7528, upload-time = "2024-12-13T09:21:27.212Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/09/ba/3d4c680a2582593b8ba568ab60b119d93542fa39d757d65aae3c4f357e29/mdformat_gfm-0.4.1-py3-none-any.whl", hash = "sha256:63c92cfa5102f55779d4e04b16a79a6a5171e658c6c479175c0955fb4ca78dde", size = 8750, upload-time = "2024-12-13T09:21:25.158Z" },
+]
+
+[[package]]
+name = "mdformat-mkdocs"
+version = "4.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdformat" },
+ { name = "mdformat-gfm" },
+ { name = "mdit-py-plugins" },
+ { name = "more-itertools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1b/85/735e11fe6a410c5005b4fb06bc2c75df56cbbcea84ad6dc101e5edae67f9/mdformat_mkdocs-4.3.0.tar.gz", hash = "sha256:d4d9b381d13900a373c1673bd72175a28d712e5ec3d9688d09e66ab4174c493c", size = 27996, upload-time = "2025-05-31T02:15:21.208Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/25/cd4edbe9e5f96048999afbd42d0c030c66c2d45f2119002e7de208e6d43a/mdformat_mkdocs-4.3.0-py3-none-any.whl", hash = "sha256:13e9512b9461c9af982c3b9e1640791d38b0835549e5f8a7ee641926feae4d58", size = 31422, upload-time = "2025-05-31T02:15:20.182Z" },
+]
+
+[[package]]
+name = "mdformat-tables"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdformat" },
+ { name = "wcwidth" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/64/fc/995ba209096bdebdeb8893d507c7b32b7e07d9a9f2cdc2ec07529947794b/mdformat_tables-1.0.0.tar.gz", hash = "sha256:a57db1ac17c4a125da794ef45539904bb8a9592e80557d525e1f169c96daa2c8", size = 6106, upload-time = "2024-08-23T23:41:33.413Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/37/d78e37d14323da3f607cd1af7daf262cb87fe614a245c15ad03bb03a2706/mdformat_tables-1.0.0-py3-none-any.whl", hash = "sha256:94cd86126141b2adc3b04c08d1441eb1272b36c39146bab078249a41c7240a9a", size = 5104, upload-time = "2024-08-23T23:41:31.863Z" },
+]
+
+[[package]]
+name = "mdit-py-plugins"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542, upload-time = "2024-09-09T20:27:49.564Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316, upload-time = "2024-09-09T20:27:48.397Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "more-itertools"
+version = "10.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.11.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.33.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
+ { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
+ { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
+ { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
+ { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
+ { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
+]
+
+[[package]]
+name = "pydot"
+version = "4.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyparsing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/35/b17cb89ff865484c6a20ef46bf9d95a5f07328292578de0b295f4a6beec2/pydot-4.0.1.tar.gz", hash = "sha256:c2148f681c4a33e08bf0e26a9e5f8e4099a82e0e2a068098f32ce86577364ad5", size = 162594, upload-time = "2025-06-17T20:09:56.454Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl", hash = "sha256:869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6", size = 37087, upload-time = "2025-06-17T20:09:55.25Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "referencing"
+version = "0.36.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" },
+]
+
+[[package]]
+name = "rfc3339-validator"
+version = "0.1.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" },
+]
+
+[[package]]
+name = "rfc3987"
+version = "1.3.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/14/bb/f1395c4b62f251a1cb503ff884500ebd248eed593f41b469f89caa3547bd/rfc3987-1.3.8.tar.gz", hash = "sha256:d3c4d257a560d544e9826b38bc81db676890c79ab9d7ac92b39c7a253d5ca733", size = 20700, upload-time = "2018-07-29T17:23:47.954Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/65/d4/f7407c3d15d5ac779c3dd34fbbc6ea2090f77bd7dd12f207ccf881551208/rfc3987-1.3.8-py2.py3-none-any.whl", hash = "sha256:10702b1e51e5658843460b189b185c0366d2cf4cff716f13111b0ea9fd2dce53", size = 13377, upload-time = "2018-07-29T17:23:45.313Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
+]
+
+[[package]]
+name = "rich-argparse"
+version = "1.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "rich" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/a6/34460d81e5534f6d2fc8e8d91ff99a5835fdca53578eac89e4f37b3a7c6d/rich_argparse-1.7.1.tar.gz", hash = "sha256:d7a493cde94043e41ea68fb43a74405fa178de981bf7b800f7a3bd02ac5c27be", size = 38094, upload-time = "2025-05-25T20:20:35.335Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/31/f6/5fc0574af5379606ffd57a4b68ed88f9b415eb222047fe023aefcc00a648/rich_argparse-1.7.1-py3-none-any.whl", hash = "sha256:a8650b42e4a4ff72127837632fba6b7da40784842f08d7395eb67a9cbd7b4bf9", size = 25357, upload-time = "2025-05-25T20:20:33.793Z" },
+]
+
+[[package]]
+name = "rpds-py"
+version = "0.25.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8c/a6/60184b7fc00dd3ca80ac635dd5b8577d444c57e8e8742cecabfacb829921/rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3", size = 27304, upload-time = "2025-05-21T12:46:12.502Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2b/da/323848a2b62abe6a0fec16ebe199dc6889c5d0a332458da8985b2980dffe/rpds_py-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:659d87430a8c8c704d52d094f5ba6fa72ef13b4d385b7e542a08fc240cb4a559", size = 364498, upload-time = "2025-05-21T12:43:54.841Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/b4/4d3820f731c80fd0cd823b3e95b9963fec681ae45ba35b5281a42382c67d/rpds_py-0.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68f6f060f0bbdfb0245267da014d3a6da9be127fe3e8cc4a68c6f833f8a23bb1", size = 350083, upload-time = "2025-05-21T12:43:56.428Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/b1/3a8ee1c9d480e8493619a437dec685d005f706b69253286f50f498cbdbcf/rpds_py-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083a9513a33e0b92cf6e7a6366036c6bb43ea595332c1ab5c8ae329e4bcc0a9c", size = 389023, upload-time = "2025-05-21T12:43:57.995Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/31/17293edcfc934dc62c3bf74a0cb449ecd549531f956b72287203e6880b87/rpds_py-0.25.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:816568614ecb22b18a010c7a12559c19f6fe993526af88e95a76d5a60b8b75fb", size = 403283, upload-time = "2025-05-21T12:43:59.546Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/ca/e0f0bc1a75a8925024f343258c8ecbd8828f8997ea2ac71e02f67b6f5299/rpds_py-0.25.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c6564c0947a7f52e4792983f8e6cf9bac140438ebf81f527a21d944f2fd0a40", size = 524634, upload-time = "2025-05-21T12:44:01.087Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/03/5d0be919037178fff33a6672ffc0afa04ea1cfcb61afd4119d1b5280ff0f/rpds_py-0.25.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c4a128527fe415d73cf1f70a9a688d06130d5810be69f3b553bf7b45e8acf79", size = 416233, upload-time = "2025-05-21T12:44:02.604Z" },
+ { url = "https://files.pythonhosted.org/packages/05/7c/8abb70f9017a231c6c961a8941403ed6557664c0913e1bf413cbdc039e75/rpds_py-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e1d7a4978ed554f095430b89ecc23f42014a50ac385eb0c4d163ce213c325", size = 390375, upload-time = "2025-05-21T12:44:04.162Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/ac/a87f339f0e066b9535074a9f403b9313fd3892d4a164d5d5f5875ac9f29f/rpds_py-0.25.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d74ec9bc0e2feb81d3f16946b005748119c0f52a153f6db6a29e8cd68636f295", size = 424537, upload-time = "2025-05-21T12:44:06.175Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/8f/8d5c1567eaf8c8afe98a838dd24de5013ce6e8f53a01bd47fe8bb06b5533/rpds_py-0.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3af5b4cc10fa41e5bc64e5c198a1b2d2864337f8fcbb9a67e747e34002ce812b", size = 566425, upload-time = "2025-05-21T12:44:08.242Z" },
+ { url = "https://files.pythonhosted.org/packages/95/33/03016a6be5663b389c8ab0bbbcca68d9e96af14faeff0a04affcb587e776/rpds_py-0.25.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79dc317a5f1c51fd9c6a0c4f48209c6b8526d0524a6904fc1076476e79b00f98", size = 595197, upload-time = "2025-05-21T12:44:10.449Z" },
+ { url = "https://files.pythonhosted.org/packages/33/8d/da9f4d3e208c82fda311bff0cf0a19579afceb77cf456e46c559a1c075ba/rpds_py-0.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1521031351865e0181bc585147624d66b3b00a84109b57fcb7a779c3ec3772cd", size = 561244, upload-time = "2025-05-21T12:44:12.387Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/b3/39d5dcf7c5f742ecd6dbc88f6f84ae54184b92f5f387a4053be2107b17f1/rpds_py-0.25.1-cp313-cp313-win32.whl", hash = "sha256:5d473be2b13600b93a5675d78f59e63b51b1ba2d0476893415dfbb5477e65b31", size = 222254, upload-time = "2025-05-21T12:44:14.261Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/19/2d6772c8eeb8302c5f834e6d0dfd83935a884e7c5ce16340c7eaf89ce925/rpds_py-0.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7b74e92a3b212390bdce1d93da9f6488c3878c1d434c5e751cbc202c5e09500", size = 234741, upload-time = "2025-05-21T12:44:16.236Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/5a/145ada26cfaf86018d0eb304fe55eafdd4f0b6b84530246bb4a7c4fb5c4b/rpds_py-0.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:dd326a81afe332ede08eb39ab75b301d5676802cdffd3a8f287a5f0b694dc3f5", size = 224830, upload-time = "2025-05-21T12:44:17.749Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ca/d435844829c384fd2c22754ff65889c5c556a675d2ed9eb0e148435c6690/rpds_py-0.25.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a58d1ed49a94d4183483a3ce0af22f20318d4a1434acee255d683ad90bf78129", size = 359668, upload-time = "2025-05-21T12:44:19.322Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/01/b056f21db3a09f89410d493d2f6614d87bb162499f98b649d1dbd2a81988/rpds_py-0.25.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f251bf23deb8332823aef1da169d5d89fa84c89f67bdfb566c49dea1fccfd50d", size = 345649, upload-time = "2025-05-21T12:44:20.962Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0f/e0d00dc991e3d40e03ca36383b44995126c36b3eafa0ccbbd19664709c88/rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd586bfa270c1103ece2109314dd423df1fa3d9719928b5d09e4840cec0d72", size = 384776, upload-time = "2025-05-21T12:44:22.516Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/a2/59374837f105f2ca79bde3c3cd1065b2f8c01678900924949f6392eab66d/rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d273f136e912aa101a9274c3145dcbddbe4bac560e77e6d5b3c9f6e0ed06d34", size = 395131, upload-time = "2025-05-21T12:44:24.147Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/dc/48e8d84887627a0fe0bac53f0b4631e90976fd5d35fff8be66b8e4f3916b/rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:666fa7b1bd0a3810a7f18f6d3a25ccd8866291fbbc3c9b912b917a6715874bb9", size = 520942, upload-time = "2025-05-21T12:44:25.915Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f5/ee056966aeae401913d37befeeab57a4a43a4f00099e0a20297f17b8f00c/rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:921954d7fbf3fccc7de8f717799304b14b6d9a45bbeec5a8d7408ccbf531faf5", size = 411330, upload-time = "2025-05-21T12:44:27.638Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/74/b2cffb46a097cefe5d17f94ede7a174184b9d158a0aeb195f39f2c0361e8/rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d86373ff19ca0441ebeb696ef64cb58b8b5cbacffcda5a0ec2f3911732a194", size = 387339, upload-time = "2025-05-21T12:44:29.292Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/9a/0ff0b375dcb5161c2b7054e7d0b7575f1680127505945f5cabaac890bc07/rpds_py-0.25.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8980cde3bb8575e7c956a530f2c217c1d6aac453474bf3ea0f9c89868b531b6", size = 418077, upload-time = "2025-05-21T12:44:30.877Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/a1/fda629bf20d6b698ae84c7c840cfb0e9e4200f664fc96e1f456f00e4ad6e/rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8eb8c84ecea987a2523e057c0d950bcb3f789696c0499290b8d7b3107a719d78", size = 562441, upload-time = "2025-05-21T12:44:32.541Z" },
+ { url = "https://files.pythonhosted.org/packages/20/15/ce4b5257f654132f326f4acd87268e1006cc071e2c59794c5bdf4bebbb51/rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e43a005671a9ed5a650f3bc39e4dbccd6d4326b24fb5ea8be5f3a43a6f576c72", size = 590750, upload-time = "2025-05-21T12:44:34.557Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/ab/e04bf58a8d375aeedb5268edcc835c6a660ebf79d4384d8e0889439448b0/rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58f77c60956501a4a627749a6dcb78dac522f249dd96b5c9f1c6af29bfacfb66", size = 558891, upload-time = "2025-05-21T12:44:37.358Z" },
+ { url = "https://files.pythonhosted.org/packages/90/82/cb8c6028a6ef6cd2b7991e2e4ced01c854b6236ecf51e81b64b569c43d73/rpds_py-0.25.1-cp313-cp313t-win32.whl", hash = "sha256:2cb9e5b5e26fc02c8a4345048cd9998c2aca7c2712bd1b36da0c72ee969a3523", size = 218718, upload-time = "2025-05-21T12:44:38.969Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/97/5a4b59697111c89477d20ba8a44df9ca16b41e737fa569d5ae8bff99e650/rpds_py-0.25.1-cp313-cp313t-win_amd64.whl", hash = "sha256:401ca1c4a20cc0510d3435d89c069fe0a9ae2ee6495135ac46bdd49ec0495763", size = 232218, upload-time = "2025-05-21T12:44:40.512Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[package]]
+name = "spec"
+version = "0.1.0"
+source = { editable = "packages/spec" }
+
+[[package]]
+name = "types-python-dateutil"
+version = "2.9.0.20250516"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ef/88/d65ed807393285204ab6e2801e5d11fbbea811adcaa979a2ed3b67a5ef41/types_python_dateutil-2.9.0.20250516.tar.gz", hash = "sha256:13e80d6c9c47df23ad773d54b2826bd52dbbb41be87c3f339381c1700ad21ee5", size = 13943, upload-time = "2025-05-16T03:06:58.385Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c5/3f/b0e8db149896005adc938a1e7f371d6d7e9eca4053a29b108978ed15e0c2/types_python_dateutil-2.9.0.20250516-py3-none-any.whl", hash = "sha256:2b2b3f57f9c6a61fba26a9c0ffb9ea5681c9b83e69cd897c6b5f668d9c0cab93", size = 14356, upload-time = "2025-05-16T03:06:57.249Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.14.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
+]
+
+[[package]]
+name = "uri-template"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" },
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.13"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" },
+]
+
+[[package]]
+name = "webcolors"
+version = "24.11.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064, upload-time = "2024-11-11T07:43:24.224Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934, upload-time = "2024-11-11T07:43:22.529Z" },
+]
diff --git a/specs/signed_doc.json b/specs/signed_doc.json
index 9706ba0d6b..280d2a240b 100644
--- a/specs/signed_doc.json
+++ b/specs/signed_doc.json
@@ -9,11 +9,19 @@
"Campaign": "5ef32d5d-f240-462c-a7a4-ba4af221fa23",
"Category": "818938c3-3139-4daa-afe6-974c78488e95",
"Comment": "b679ded3-0e7c-41ba-89f8-da62a17898ea",
- "Decision": "788ff4c6-d65a-451f-bb33-575fe056b411",
+ "Contest": "788ff4c6-d65a-451f-bb33-575fe056b411",
+ "Delegation": "764f17fb-cc50-4979-b14a-b213dbac5994",
+ "FormTemplate": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
"ModerationAction": "a5d232b8-5e03-4117-9afd-be32b878fcdd",
+ "Nomination": "bf9abd97-5d1f-4429-8e80-740fea371a9c",
+ "Parameters": "60185874-7e13-407c-a06c-238ffe637ae6",
+ "PresentationTemplate": "cb99b9bd-681a-49d8-9836-89107c02e8ef",
+ "Profile": "0f2c86a2-ffda-40b0-ad38-23709e1c10b3",
"Proposal": "7808d2ba-d511-40af-84e8-c0d1625fdfdc",
- "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65",
- "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f"
+ "RegisteredProposer": "7311c63b-95c6-402e-a258-f9bf622093eb",
+ "RegisteredRep": "94579df1-a6dc-433b-a8e8-910c5dc2f0e3",
+ "RegisteredUser": "ff4b7724-3db5-44cd-a433-78ba6d29505e",
+ "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65"
},
"cddlDefinitions": {
"COSE_Document_Header_Map": {
@@ -115,6 +123,14 @@
"def": "bytes",
"requires": []
},
+ "chain": {
+ "comment": "Reference to the previous Signed Document in a sequence.\n* `height` is of the CURRENT block.\n* `document_ref` is *ONLY* omitted in the very first document in a sequence.",
+ "def": "[height, ? document_ref]",
+ "requires": [
+ "height",
+ "document_ref"
+ ]
+ },
"cid": {
"comment": "IPLD content identifier\nTODO: add size limits if possible",
"def": "#6.42(bytes)",
@@ -144,14 +160,21 @@
]
},
"document_ref": {
- "comment": "Reference to another Signed Document",
- "def": "[ 1* [\n document_id, \n document_ver, \n document_locator\n] ]",
+ "comment": "Reference to a single Signed Document",
+ "def": "[\n document_id, \n document_ver, \n document_locator\n]",
"requires": [
"document_id",
"document_ver",
"document_locator"
]
},
+ "document_refs": {
+ "comment": "Reference to one or more Signed Documents",
+ "def": "[ 1* document_ref ]",
+ "requires": [
+ "document_ref"
+ ]
+ },
"document_type": {
"comment": "Document Type",
"def": "[ 1* uuid_v4 ]",
@@ -168,6 +191,11 @@
"uuid_v7"
]
},
+ "height": {
+ "comment": "The consecutive sequence number of the current document \nin the chain.\nThe very first document in a sequence is numbered `0` and it\n*MUST ONLY* increment by one for each successive document in\nthe sequence.\n\nThe FINAL sequence number is encoded with the current height\nsequence value, negated. \n\nFor example the following values for height define a chain\nthat has 5 documents in the sequence 0-4, the final height \nis negated to indicate the end of the chain:\n`0, 1, 2, 3, -4`\n\nNo subsequent document can be chained to a sequence that has\na final chain height.",
+ "def": "int",
+ "requires": []
+ },
"http_content_encoding": {
"comment": "Supported Content Encoding Types",
"def": "tstr .eq \"br\"",
@@ -179,8 +207,8 @@
"requires": []
},
"media_type": {
- "comment": "Supported Content Media Types.\nIf uint is used, only CoAP Content Formats that match the string format are allowed.",
- "def": "(\n (uint .eq (50 / 60)) / \n (tstr .eq (\n \"application/json\" /\n \"application/schema+json\" /\n \"application/cbor\" /\n \"application/cddl\"\n ))\n)",
+ "comment": "Supported Content Media Types.\nIf the Media Type is supported by COAP, then the `uint` CoAP encoded\nversion of the media type must be used, in preference to the string.",
+ "def": "(\n (uint .eq (0 / 50 / 60 / 20000)) / \n (tstr .eq (\n \"application/cbor\" /\n \"application/cddl\" /\n \"application/json\" /\n \"application/schema+json\" /\n \"text/css; charset=utf-8\" /\n \"text/css; charset=utf-8; template=handlebars\" /\n \"text/html; charset=utf-8\" /\n \"text/html; charset=utf-8; template=handlebars\" /\n \"text/markdown; charset=utf-8\" /\n \"text/markdown; charset=utf-8; template=handlebars\" /\n \"text/plain; charset=utf-8\" /\n \"text/plain; charset=utf-8; template=handlebars\"\n ))\n)",
"requires": []
},
"revocations": {
@@ -221,17 +249,43 @@
"contentTypes": {
"application/cbor": {
"coap_type": 60,
- "description": "RFC8949 Binary CBOR Encoded Document"
+ "description": "An RFC8949 Binary CBOR Encoded Document."
},
"application/cddl": {
- "description": "CDDL Document; Note: \n* This is an unofficial media type\n* RFC9165 Additional Control Operators for CDDL are supported. \n* Must not have Modules, schema must be self-contained."
+ "description": "A CDDL Document.\n\nNote: \n\n* This is an unofficial media type\n* RFC9165 Additional Control Operators for CDDL are supported. \n* Must not have Modules, schema must be self-contained."
},
"application/json": {
"coap_type": 50,
"description": "JSON Document"
},
"application/schema+json": {
- "description": "JSON Schema Draft 7 Document; Note: \n* This is currently an unofficial media type.\n* Draft 7 is used because of its wide support by tooling."
+ "description": "A JSON Schema Draft 2020-12 Document.\n\nNote: \n\n* This is currently an unofficial media type."
+ },
+ "text/css; charset=utf-8": {
+ "coap_type": 20000,
+ "description": "CSS Content used for styling HTML.\nCSS should use the least set of features possible to achieve\nthe desired presentation to ensure the broadest compatibility."
+ },
+ "text/css; charset=utf-8; template=handlebars": {
+ "description": "CSS Content used for styling HTML.\nCSS should use the least set of features possible to achieve\nthe desired presentation to ensure the broadest compatibility.\n\nThe text includes Handlebars type template fields that need\nprocessing and replacement prior to display."
+ },
+ "text/html; charset=utf-8": {
+ "description": "Formatted text using HTML5 markup for rich text. \nOnly HTML5 syntax is supported."
+ },
+ "text/html; charset=utf-8; template=handlebars": {
+ "description": "Formatted text using HTML5 markup for rich text. \nOnly HTML5 syntax is supported.\n\nThe text includes Handlebars type template fields that need\nprocessing and replacement prior to display."
+ },
+ "text/markdown; charset=utf-8": {
+ "description": "Formatted text using Markdown for rich text. \nMarkdown formatting is as defined by CommonMark.\n\nIF the document includes HTML, then HTML5 syntax only is supported.\n\nThe following Markdown Extensions are also supported:\n\n* None"
+ },
+ "text/markdown; charset=utf-8; template=handlebars": {
+ "description": "Formatted text using Markdown for rich text. \nMarkdown formatting is as defined by CommonMark.\n\nIF the document includes HTML, then HTML5 syntax only is supported.\n\nThe following Markdown Extensions are also supported:\n\n* None\n\nThe text includes Handlebars type template fields that need\nprocessing and replacement prior to display."
+ },
+ "text/plain; charset=utf-8": {
+ "coap_type": 0,
+ "description": "Plain Text with no markup or special formatting.\nMultiline Plain Text *MUST* always interpret `\n` \nas a hard line break."
+ },
+ "text/plain; charset=utf-8; template=handlebars": {
+ "description": "Plain Text with no markup or special formatting.\nMultiline Plain Text *MUST* always interpret `\n` \nas a hard line break.\n\nThe text includes Handlebars type template fields that need\nprocessing and replacement prior to display."
}
},
"copyright": {
@@ -253,56 +307,71 @@
"changes": "* Use generalized parameters.",
"modified": "2025-05-05",
"version": "0.03"
+ },
+ {
+ "changes": "* Improve and make document serialization more repeatable, and stricter.\n* TODO: Define Systems parameters\n* TODO: Define DReps documents.\n* TODO: Define Proposer Profiles.\n* TODO: Define Role 0 Profile.",
+ "modified": "2025-05-30",
+ "version": "0.04"
}
]
},
- "coseHeaderFormats": {
- "Catalyst ID": {
- "cddl": "catalyst_id_kid",
- "description": "KID (Catalyst ID URI)"
- },
- "HTTP Content Encoding": {
- "cddl": "http_content_encoding",
- "description": "Encoding if any on the payload."
- },
- "Media Type": {
- "cddl": "media_type",
- "description": "A Media Type string which identifies the payload."
- }
- },
- "cose_headers": {
- "content type": {
- "coseLabel": 3,
- "description": "Media Type/s allowed in the Payload",
- "format": "Media Type",
- "required": "yes",
- "value": [
- "application/json",
- "application/schema+json",
- "application/cbor",
- "application/cddl"
- ]
+ "cose": {
+ "headerFormats": {
+ "Catalyst ID": {
+ "cddl": "catalyst_id_kid",
+ "description": "KID (Catalyst ID URI)"
+ },
+ "HTTP Content Encoding": {
+ "cddl": "http_content_encoding",
+ "description": "Encoding if any on the payload."
+ },
+ "Media Type": {
+ "cddl": "media_type",
+ "description": "A Media Type string which identifies the payload."
+ }
},
- "content-encoding": {
- "coseLabel": "content-encoding",
- "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
- "format": "HTTP Content Encoding",
- "required": "optional",
- "value": [
- "br"
- ]
- }
- },
- "cose_headers_order": [
- "content type",
- "content-encoding"
- ],
- "cose_signature_headers": {
- "kid": {
- "coseLabel": 4,
- "description": "Catalyst ID URI identifying the Public Key.\n\nThe `kid` is a UTF-8 encoded Catalyst ID URI.\nAny `kid` URI which conforms to the Catalyst ID specification may be used.\nThe Catalyst ID unambiguously defines both the signing keys and signing algorithm\nused to sign the protected portion of the document.\t\t\t",
- "format": "Catalyst ID",
- "required": "yes"
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": [
+ "application/cbor",
+ "application/cddl",
+ "application/json",
+ "application/schema+json",
+ "text/css; charset=utf-8",
+ "text/css; charset=utf-8; template=handlebars",
+ "text/html; charset=utf-8",
+ "text/html; charset=utf-8; template=handlebars",
+ "text/markdown; charset=utf-8",
+ "text/markdown; charset=utf-8; template=handlebars",
+ "text/plain; charset=utf-8",
+ "text/plain; charset=utf-8; template=handlebars"
+ ]
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "headersOrder": [
+ "content type",
+ "content-encoding"
+ ],
+ "signature_headers": {
+ "kid": {
+ "coseLabel": 4,
+ "description": "Catalyst ID URI identifying the Public Key.\n\nThe `kid` is a UTF-8 encoded Catalyst ID URI.\nAny `kid` URI which conforms to the Catalyst ID specification may be used.\nThe Catalyst ID unambiguously defines both the signing keys and signing algorithm\nused to sign the protected portion of the document.\t\t\t",
+ "format": "Catalyst ID",
+ "required": "yes"
+ }
}
},
"doc_clusters": {
@@ -316,8 +385,11 @@
},
"docs": {
"Brand Parameters": {
- "authors": {},
- "description": "Parameters which define this brand within the system.",
+ "authors": {
+ "Nathan Bogale": "nathan.bogale@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "description": "Brand Parameters define the parameter data required for the\nsystem at the Brand level.\n\nParameter Data includes things such as:\n\n* Functional parameters\n* Timeline data\n* Branded Content and Copy\n\nThe content of the parameters is defined solely by the \nBrand Parameters Form Template.\n\nThis allows parameters to vary based on individual system\nrequirements over time.\n\nFunctional Parameters are mapped using the (TBD Functional Parameters Map).\n\nThe payload of a Brand is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -337,109 +409,120 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "excluded",
+ "required": "optional",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Brand Parameters Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "Brand Parameters Document controlling the Brand \nwithin a Brand.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ },
"signers": {
"roles": {
- "user": [
- "Registered"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
- "author": true
+ "author": true,
+ "collaborators": true
}
},
"type": [
+ "60185874-7e13-407c-a06c-238ffe637ae6",
"ebcabeeb-5bc5-4f95-91e8-cab8ca724172"
],
+ "validation": "No extra validation defined.",
"versions": [
{
"changes": "* First Published Version",
"modified": "2025-04-04",
"version": "0.01"
+ },
+ {
+ "changes": "* Generalized as another kind of form data document",
+ "modified": "2025-06-20",
+ "version": "0.02"
}
]
},
- "Campaign Parameters": {
+ "Brand Parameters Form Template": {
"authors": {},
- "description": "Parameters which define a Campaign within a Brand in the system.",
+ "description": "A Brand Parameters Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Brand Parameters Form Template is a JSON Schema Document.\n\nBrand Parameters entry *SHOULD* use the hints when collecting \ndata defined by the Brand Parameters Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Brand Parameters Presentation Template can be used to\nformat the Brand Parameters data for presentation.\n\nThe Brand Parameters Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Brand Parameters.\n\nThe payload of a Brand Parameters is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
"description": "Media Type/s allowed in the Payload",
"format": "Media Type",
"required": "yes",
- "value": "application/json"
+ "value": "application/schema+json"
},
"content-encoding": {
"coseLabel": "content-encoding",
@@ -452,93 +535,92 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": "Brand Parameters",
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
"required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nBrand Parameters Document."
+ },
"signers": {
"roles": {
- "user": [
- "Registered"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
"author": true
}
},
"type": [
- "5ef32d5d-f240-462c-a7a4-ba4af221fa23"
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "ebcabeeb-5bc5-4f95-91e8-cab8ca724172"
],
"versions": [
{
@@ -550,12 +632,20 @@
"changes": "* Use generalized parameters.",
"modified": "2025-05-05",
"version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
}
]
},
- "Category Parameters": {
- "authors": {},
- "description": "Parameters which define a Category withing a Campaign under a Brand in the system.",
+ "Campaign Parameters": {
+ "authors": {
+ "Nathan Bogale": "nathan.bogale@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "description": "Campaign Parameters define the parameter data required for the\nsystem at the Campaign level.\n\nParameter Data includes things such as:\n\n* Functional parameters\n* Timeline data\n* Branded Content and Copy\n\nThe content of the parameters is defined solely by the \nCampaign Parameters Form Template.\n\nThis allows parameters to vary based on individual system\nrequirements over time.\n\nFunctional Parameters are mapped using the (TBD Functional Parameters Map).\n\nThe payload of a Campaign is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -575,94 +665,100 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "excluded",
+ "required": "optional",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
"multiple": false,
"required": "yes",
- "type": "Campaign Parameters",
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "type": "Brand Parameters",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Campaign Parameters Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "Campaign Parameters Document controlling the Campaign \nwithin a Brand.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ },
"signers": {
"roles": {
- "user": [
- "Registered"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
- "author": true
+ "author": true,
+ "collaborators": true
}
},
"type": [
- "818938c3-3139-4daa-afe6-974c78488e95"
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "5ef32d5d-f240-462c-a7a4-ba4af221fa23"
],
+ "validation": "The Campaign Parameters Document *MUST* be linked through `parameters` to \nits Brand Parameters Document.",
"versions": [
{
"changes": "* First Published Version",
@@ -670,22 +766,22 @@
"version": "0.01"
},
{
- "changes": "* Use generalized parameters.",
- "modified": "2025-05-05",
- "version": "0.03"
+ "changes": "* Generalized as another kind of form data document",
+ "modified": "2025-06-20",
+ "version": "0.02"
}
]
},
- "Comment Moderation Action": {
+ "Campaign Parameters Form Template": {
"authors": {},
- "description": "A Moderation Action performed on any Comment.",
+ "description": "A Campaign Parameters Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Campaign Parameters Form Template is a JSON Schema Document.\n\nCampaign Parameters entry *SHOULD* use the hints when collecting \ndata defined by the Campaign Parameters Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Campaign Parameters Presentation Template can be used to\nformat the Campaign Parameters data for presentation.\n\nThe Campaign Parameters Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Campaign Parameters.\n\nThe payload of a Campaign Parameters is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
"description": "Media Type/s allowed in the Payload",
"format": "Media Type",
"required": "yes",
- "value": "application/json"
+ "value": "application/schema+json"
},
"content-encoding": {
"coseLabel": "content-encoding",
@@ -698,109 +794,117 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": [
- "Proposal Comment"
- ],
+ "required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
"required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nCampaign Parameters Document."
+ },
"signers": {
"roles": {
- "user": [
- "Registered"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
"author": true
}
},
"type": [
- "5e60e623-ad02-4a1b-a1ac-406db978ee48",
- "b679ded3-0e7c-41ba-89f8-da62a17898ea",
- "a5d232b8-5e03-4117-9afd-be32b878fcdd"
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "5ef32d5d-f240-462c-a7a4-ba4af221fa23"
],
"versions": [
{
"changes": "* First Published Version",
"modified": "2025-04-04",
"version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
}
]
},
- "Decision Parameters": {
- "authors": {},
- "description": "Parameters which define an individual voting event.",
+ "Category Parameters": {
+ "authors": {
+ "Nathan Bogale": "nathan.bogale@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "description": "Category Parameters define the parameter data required for the\nsystem at the Category level.\n\nParameter Data includes things such as:\n\n* Functional parameters\n* Timeline data\n* Branded Content and Copy\n\nThe content of the parameters is defined solely by the \nCategory Parameters Form Template.\n\nThis allows parameters to vary based on individual system\nrequirements over time.\n\nFunctional Parameters are mapped using the (TBD Functional Parameters Map).\n\nThe payload of a Category is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -820,98 +924,100 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "excluded",
+ "required": "optional",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
"multiple": false,
"required": "yes",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "type": "Campaign Parameters",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Category Parameters Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "Category Parameters Document controlling the Category \nwithin a Campaign.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ },
"signers": {
"roles": {
- "user": [
- "Registered"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
- "author": true
+ "author": true,
+ "collaborators": true
}
},
"type": [
- "788ff4c6-d65a-451f-bb33-575fe056b411"
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "818938c3-3139-4daa-afe6-974c78488e95"
],
+ "validation": "The Category Parameters Document *MUST* be linked through `parameters` to \nits Campaign Parameters Document.",
"versions": [
{
"changes": "* First Published Version",
@@ -919,28 +1025,22 @@
"version": "0.01"
},
{
- "changes": "* Use generalized parameters.",
- "modified": "2025-05-05",
- "version": "0.03"
+ "changes": "* Generalized as another kind of form data document",
+ "modified": "2025-06-20",
+ "version": "0.02"
}
]
},
- "Proposal": {
- "authors": {
- "Steven Johnson": "steven.johnson@iohk.io"
- },
- "business_logic": {
- "back_end": "Before accepting a new proposal to be published, the backend will ensure:\n\n* The document has been signed by a valid author or collaborator.\n* That the signer of the document was a registered proposer\n* That the document was signed with their proposers key\n* That all listed `collaborators` are registered as proposers.\n* That the document has been signed validly according to the [validation](#validation) rules.",
- "front_end": "As validity of the documents is currently enforced by the backend, \nthe front end does not need to validate the document has been signed\ncorrectly.\nIt may do so, but it is not required."
- },
- "description": "A Proposal is a document which describes a proposed solution or project to\naddress the criteria of a category within a campaign.\n\nThe proposal itself is a draft document, it is not submitted for consideration\nunless a `Proposal Submission Action` is submitted which references it.\n\nProposals themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal is controlled by its template.",
+ "Category Parameters Form Template": {
+ "authors": {},
+ "description": "A Category Parameters Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Category Parameters Form Template is a JSON Schema Document.\n\nCategory Parameters entry *SHOULD* use the hints when collecting \ndata defined by the Category Parameters Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Category Parameters Presentation Template can be used to\nformat the Category Parameters data for presentation.\n\nThe Category Parameters Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Category Parameters.\n\nThe payload of a Category Parameters is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
"description": "Media Type/s allowed in the Payload",
"format": "Media Type",
"required": "yes",
- "value": "application/json"
+ "value": "application/schema+json"
},
"content-encoding": {
"coseLabel": "content-encoding",
@@ -953,84 +1053,68 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "optional",
+ "required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": [
- "template"
- ],
- "multiple": false,
- "required": "yes",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "optional",
+ "required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": "Proposal Template",
+ "required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -1038,23 +1122,24 @@
},
"notes": [],
"payload": {
- "description": "Proposal Document drafted for submission to a category of a campaign.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nCategory Parameters Document."
},
"signers": {
"roles": {
- "user": [
- "Proposer"
- ]
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
},
"update": {
- "author": true,
- "collaborators": true
+ "author": true
}
},
"type": [
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "818938c3-3139-4daa-afe6-974c78488e95"
],
- "validation": "The first version of a Proposal *MUST* be signed by the original author.\nIt may optionally be co-signed by any of the listed `collaborators`.\nIt may not be signed by anyone else.\n\nSubsequent Versions can be signed/co-signed by either the Original Author of the first version,\nOR any of the listed `collaborators` in the immediately previous version.\nThis allows any collaborator to update the next version of a document, provided they are still a collaborator.\nIt is valid for a proposal to be signed by a collaborator \nwho is no longer listed as in the `collaborators`\nof the document they are signing, provided they are listed as a collaborator in the immediately previous document version.\nThis allows for a collaborator to make an update to the document which removes themselves\nfrom the `collaborators` list.\n\nAll versions of the document *MUST* list the author as the original author.\nThe Author can not be changed by any document revision.",
"versions": [
{
"changes": "* First Published Version",
@@ -1065,16 +1150,17 @@
"changes": "* Use generalized parameters.",
"modified": "2025-05-05",
"version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
}
]
},
- "Proposal Comment": {
+ "Comment Moderation Action": {
"authors": {},
- "business_logic": {
- "back_end": "The backend will only validate the document being referenced exists, \nand the integrity of the `ref` and `reply` metadata fields is correct.",
- "front_end": "Comments are valid for any version of the document, however\nas comments refer to a specific version of a document, they may\nlose context when displayed against the latest version of a document.\nIn these cases, the front end should clearly show that a comment was on\na different version of the document.\n\nIf the front end posts a reply to another comment: \n\n* it should reference the comment being replied to in the `reply` field. \n* The `ref` field must refer to the same document, but can be a different version."
- },
- "description": "A Proposal Comment is a document which comments on a referenced Proposal document.\n\nProposal Comments themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal comment is controlled by its template.",
+ "description": "A Moderation Action performed on any Comment.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -1094,100 +1180,79 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": [
- "ref",
- "template"
- ],
- "multiple": false,
- "required": "yes",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
"multiple": false,
"required": "yes",
- "type": "Proposal",
+ "type": [
+ "Proposal Comment"
+ ],
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
- "type": "Proposal Comment",
+ "required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "optional",
+ "required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
- "required": "optional",
+ "required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": "Proposal Comment Template",
+ "required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
- "payload": {
- "description": "JSON Document which must validate against the referenced template."
- },
"signers": {
"roles": {
"user": [
@@ -1199,118 +1264,98 @@
}
},
"type": [
+ "5e60e623-ad02-4a1b-a1ac-406db978ee48",
"b679ded3-0e7c-41ba-89f8-da62a17898ea",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ "a5d232b8-5e03-4117-9afd-be32b878fcdd"
],
- "validation": "A comment which is a reply *MUST* reference the same document.\nIt may reference a different version of the document.",
"versions": [
{
"changes": "* First Published Version",
"modified": "2025-04-04",
"version": "0.01"
- },
- {
- "changes": "* Use generalized parameters.",
- "modified": "2025-05-05",
- "version": "0.03"
}
]
},
- "Proposal Comment Meta Template": {
- "authors": {},
- "description": "## Proposal Comment Meta Template Document\n\nA Proposal Comment Meta Template is used to enforce functional requirements\nare met in any Proposal Comment Template.\n\nThe payload of a proposal comment template is controlled by its meta template.",
- "headers": {
- "content type": {
- "coseLabel": 3,
- "description": "Media Type/s allowed in the Payload",
- "format": "Media Type",
- "required": "yes",
- "value": "application/schema+json"
- },
- "content-encoding": {
- "coseLabel": "content-encoding",
- "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
- "format": "HTTP Content Encoding",
- "required": "optional",
- "value": [
- "br"
- ]
- }
+ "Contest Delegation": {
+ "authors": {
+ "Neil McAuliffe": "neil.mcauliffe@iohk.io"
+ },
+ "business_logic": {
+ "back_end": "* Verifies that the voter and Representative are valid and registered for the category.\n* Records the delegation of voting power from the voter to the Representative.",
+ "front_end": "* Allows a voter to select a Representative from a list of eligible candidates for a category.\n* The voter signs this document to confirm their delegation choice."
},
+ "description": "Delegation by a Registered User to a Representative for\na contest.\n\nThis delegation allows votes cast by the Representative\nto use the voting power of the delegating User, in addition\nto their own personal voting power and that of all other Users \nwho delegate to the same Representative.\n\nDelegation is for a specific Contest.\nMultiple Delegations must be published if there are multiple\nContests within a Brand/Campaign or Category.\n\nThis is because different Contests may have different rules.\nAnd not all Representatives will choose to nominate\nfor every Contest.",
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
+ "linked_refs": [
+ "ref"
+ ],
"multiple": false,
"required": "yes",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "type": "Contest Parameters",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Rep Nomination",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
"required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -1318,50 +1363,45 @@
},
"notes": [],
"payload": {
- "description": "JSON Schema document which ensures the minimum required functional requirements\nof the Proposal Comment Template are met.\n\nThis ensures that payloads can be reliably interpreted by business logic processes, \nwhile allowing for flexibility to capture extended information.",
- "schema": "https://json-schema.org/draft-07/schema"
+ "description": " A minimal payload indicating the intended status of the delegation.\n 'active' creates or affirms the delegation.\n 'revoked' withdraws the delegation.",
+ "nil": true
},
"signers": {
"roles": {
- "admin": [
- "Root Admin",
- "Brand Admin"
- ],
- "user": []
+ "user": [
+ "Registered"
+ ]
},
"update": {
"author": true
}
},
"type": [
- "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
- "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
- "b679ded3-0e7c-41ba-89f8-da62a17898ea",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ "764f17fb-cc50-4979-b14a-b213dbac5994",
+ "788ff4c6-d65a-451f-bb33-575fe056b411"
],
+ "validation": "* The `parameters` metadata *MUST* point to the same Contest as the \n\tNomination of the Representative.\n* The 'ref' metadata field MUST point to a valid 'Representative Nomination'.\n* The payload MUST be nil.\n\nA Representative *MUST* Delegate to their latest Nomination for a Category,\notherwise their Nomination is invalid.\n\nThis is because Delegation points to a *SPECIFIC* Nomination, and it\n*MUST* be the latest for the Representative on the Contest.\nAs the Nomination contains information that the User relies on\nwhen choosing to delegate, changing that information could have a \nreal and detrimental result in the Delegation choice.\nTherefore, for a Delegation to be valid, it *MUST* point to the\nlatest Nomination for a Representative.",
"versions": [
{
"changes": "* First Published Version",
- "modified": "2025-04-04",
+ "modified": "2025-06-19",
"version": "0.01"
- },
- {
- "changes": "* Use generalized parameters.",
- "modified": "2025-05-05",
- "version": "0.03"
}
]
},
- "Proposal Comment Template": {
- "authors": {},
- "description": "## Proposal Comment Template Document\n\nA Proposal Comment Template defines the allowed payload contents of a\nlinked proposal comment.\n\nProposal comments themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal comment is controlled by its template.",
+ "Contest Parameters": {
+ "authors": {
+ "Nathan Bogale": "nathan.bogale@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "description": "Contest Parameters define the parameter data required for the\nsystem at the Contest level.\n\nParameter Data includes things such as:\n\n* Functional parameters\n* Timeline data\n* Branded Content and Copy\n\nThe content of the parameters is defined solely by the \nContest Parameters Form Template.\n\nThis allows parameters to vary based on individual system\nrequirements over time.\n\nFunctional Parameters are mapped using the (TBD Functional Parameters Map).\n\nThe payload of a Contest is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
"description": "Media Type/s allowed in the Payload",
"format": "Media Type",
"required": "yes",
- "value": "application/schema+json"
+ "value": "application/json"
},
"content-encoding": {
"coseLabel": "content-encoding",
@@ -1374,23 +1414,26 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "excluded",
+ "required": "optional",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
"multiple": false,
@@ -1400,56 +1443,49 @@
"Campaign Parameters",
"Category Parameters"
],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
"multiple": false,
- "required": "optional",
- "type": "Proposal Comment Meta Template",
+ "required": "yes",
+ "type": "Contest Parameters Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -1457,25 +1493,25 @@
},
"notes": [],
"payload": {
- "description": "JSON Schema document which defines the content of the Proposal Comments."
+ "description": "Contest Parameters Document controlling the Contest \nwithin a Brand/Campaign/Category.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
},
"signers": {
"roles": {
"admin": [
- "Brand Admin",
- "Campaign Admin"
+ "Brand Admin"
],
"user": []
},
"update": {
- "author": true
+ "author": true,
+ "collaborators": true
}
},
"type": [
- "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
- "b679ded3-0e7c-41ba-89f8-da62a17898ea",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "788ff4c6-d65a-451f-bb33-575fe056b411"
],
+ "validation": "The Contest Parameters Document *MUST* be linked through `parameters` to \nits Brand/Campaign/Category Parameters Document.",
"versions": [
{
"changes": "* First Published Version",
@@ -1483,15 +1519,15 @@
"version": "0.01"
},
{
- "changes": "* Use generalized parameters.",
- "modified": "2025-05-05",
- "version": "0.03"
+ "changes": "* Generalized as another kind of form data document",
+ "modified": "2025-06-20",
+ "version": "0.02"
}
]
},
- "Proposal Meta Template": {
+ "Contest Parameters Form Template": {
"authors": {},
- "description": "## Proposal Meta Template Document\n\nA Proposal Meta Template is used to enforce functional requirements\nare met in any Proposal Template.\n\nThe payload of a proposal template is controlled by its meta template.",
+ "description": "A Contest Parameters Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Contest Parameters Form Template is a JSON Schema Document.\n\nContest Parameters entry *SHOULD* use the hints when collecting \ndata defined by the Contest Parameters Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Contest Parameters Presentation Template can be used to\nformat the Contest Parameters data for presentation.\n\nThe Contest Parameters Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Contest Parameters.\n\nThe payload of a Contest Parameters is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -1511,79 +1547,68 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
"required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -1591,13 +1616,11 @@
},
"notes": [],
"payload": {
- "description": "JSON Schema document which ensures the minimum required functional requirements\nof the Proposal Template are met.\n\nThis ensures that payloads can be reliably interpreted by business logic processes, \nwhile allowing for flexibility to capture extended information.",
- "schema": "https://json-schema.org/draft-07/schema"
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nContest Parameters Document."
},
"signers": {
"roles": {
"admin": [
- "Root Admin",
"Brand Admin"
],
"user": []
@@ -1608,8 +1631,8 @@
},
"type": [
"0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
- "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ "60185874-7e13-407c-a06c-238ffe637ae6",
+ "788ff4c6-d65a-451f-bb33-575fe056b411"
],
"versions": [
{
@@ -1621,12 +1644,23 @@
"changes": "* Use generalized parameters.",
"modified": "2025-05-05",
"version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
}
]
},
- "Proposal Moderation Action": {
- "authors": {},
- "description": "A Moderation action performed on a Proposal.",
+ "Proposal": {
+ "authors": {
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "business_logic": {
+ "back_end": "Before accepting a new proposal to be published, the backend will ensure:\n\n* The document has been signed by a valid author or collaborator.\n* That the signer of the document was a registered proposer\n* That the document was signed with their proposers key\n* That all listed `collaborators` are registered as proposers.\n* That the document has been signed validly according to the [validation](#validation) rules.",
+ "front_end": "As validity of the documents is currently enforced by the backend, \nthe front end does not need to validate the document has been signed\ncorrectly.\nIt may do so, but it is not required."
+ },
+ "description": "A Proposal is a document which describes a proposed solution or project to\naddress the criteria of a category within a campaign.\n\nThe proposal itself is a draft document, it is not submitted for consideration\nunless a `Proposal Submission Action` is submitted which references it.\n\nProposals themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -1646,111 +1680,124 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
- "required": "excluded",
+ "required": "optional",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "linked_refs": [
+ "template"
+ ],
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "yes",
- "type": "Proposal",
+ "required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Proposal Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
}
},
"notes": [],
+ "payload": {
+ "description": "Proposal Document drafted for submission to a category of a campaign.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ },
"signers": {
"roles": {
"user": [
- "Registered"
+ "Proposer"
]
},
"update": {
- "author": true
+ "author": true,
+ "collaborators": true
}
},
"type": [
- "5e60e623-ad02-4a1b-a1ac-406db978ee48",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc",
- "a5d232b8-5e03-4117-9afd-be32b878fcdd"
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
],
+ "validation": "The first version of a Proposal *MUST* be signed by the original author.\nIt may optionally be co-signed by any of the listed `collaborators`.\nIt may not be signed by anyone else.\n\nSubsequent Versions can be signed/co-signed by either the Original Author of the first version,\nOR any of the listed `collaborators` in the immediately previous version.\nThis allows any collaborator to update the next version of a document, provided they are still a collaborator.\nIt is valid for a proposal to be signed by a collaborator \nwho is no longer listed as in the `collaborators`\nof the document they are signing, provided they are listed as a collaborator in the immediately previous document version.\nThis allows for a collaborator to make an update to the document which removes themselves\nfrom the `collaborators` list.\n\nAll versions of the document *MUST* list the author as the original author.\nThe Author can not be changed by any document revision.",
"versions": [
{
"changes": "* First Published Version",
"modified": "2025-04-04",
"version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
}
]
},
- "Proposal Submission Action": {
+ "Proposal Comment": {
"authors": {},
"business_logic": {
- "back_end": "A Submitted proposal with collaborators *MUST* have \na `final` submission by *ALL* listed `collaborators`.\nIf any `collaborator` has not submitted a `final` submission by the deadline, then the proposal \nis not considered `final` and will not be considered in the category it was being submitted to.",
- "front_end": "A proposal with `collaborators` will not be shown as having a confirmed collaborator,\nunless there exists a `draft` or `final` proposal submission from that collaborator.\n\nAny document that lists a collaborator should be highlighted to that collaborator so\nthey can take appropriate action, such as:\n\n* Confirm they are a collaborator by submitting this document as `draft`\n* Agree to being a collaborator on the final submission by submitting this document as `final`\n* Hide themselves from the collaborators list but do not remove themselves by submitting `hide`\n* Remove themselves permanently as a collaborator by publishing a new version with them removed.\n\nTo eliminate the necessity for collaborators to accept collaboration on every version, \nthey will be considered as agreeing to be a collaborator on any version of the document\nthat lists them, if their latest submission is `draft` or `final`.\n\nIf their latest submission on a document is `hide` they should be considered to not\nhave agreed to be a collaborator.\n\n*NOTE* `final` status ONLY applies to the exactly referenced document and version."
+ "back_end": "The backend will only validate the document being referenced exists, \nand the integrity of the `ref` and `reply` metadata fields is correct.",
+ "front_end": "Comments are valid for any version of the document, however\nas comments refer to a specific version of a document, they may\nlose context when displayed against the latest version of a document.\nIn these cases, the front end should clearly show that a comment was on\na different version of the document.\n\nIf the front end posts a reply to another comment: \n\n* it should reference the comment being replied to in the `reply` field. \n* The `ref` field must refer to the same document, but can be a different version."
},
- "description": "## Proposal Submission Action\n\nA Proposal Submission Action is a document which can attempt to either submit a \nparticular version of a proposal into a campaign, or withdraw it.\n\nThe last action on the document ts the action which takes effect at the deadline.\n\nFor multiple collaborators, multiple submission actions can be posted independently, \nbut none of them will take effect until ALL collaborators have posted equivalent actions.\n\nFor example, three collaborators Alice/Bob/Claire can each post one submission action\nfor the same document. \nUnless they all submit the same version of the proposal\nthe proposal will not be seen as submitted.\n\nThe payload is a fixed format.",
+ "description": "A Proposal Comment is a document which comments on a referenced Proposal document.\n\nProposal Comments themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal comment is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -1770,26 +1817,30 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": [
- "ref"
+ "ref",
+ "template"
],
"multiple": false,
"required": "yes",
@@ -1798,56 +1849,55 @@
"Campaign Parameters",
"Category Parameters"
],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"linked_refs": null,
- "multiple": true,
+ "multiple": false,
"required": "yes",
"type": "Proposal",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "optional",
+ "type": "Proposal Comment",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
- "required": "excluded",
+ "required": "optional",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
- "required": "excluded",
+ "required": "optional",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "required": "excluded",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Proposal Comment Form Template",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -1855,64 +1905,23 @@
},
"notes": [],
"payload": {
- "description": "The kind of action is controlled by this payload.\nThe Payload is a JSON Document, and must conform to this schema.\n\nStates:\n\n* `final` : All collaborators must publish a `final` status for the proposal to be `final`.\n* `draft` : Reverses the previous `final` state for a signer and accepts collaborator status to a document. \n* `hide` : Requests the proposal be hidden (not final, but a hidden draft). \n\t\t\t`hide` is only actioned if sent by the author, \n\t\t\tfor a collaborator it identified that they do not wish to be listed as a `collaborator`.",
- "schema": {
- "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json",
- "$schema": "http://json-schema.org/draft-07/schema#",
- "additionalProperties": false,
- "definitions": {
- "action": {
- "description": "The action being performed on the Proposal.",
- "enum": [
- "final",
- "draft",
- "hide"
- ],
- "type": "string"
- }
- },
- "description": "Structure of the payload of a Proposal Submission Action.",
- "maintainers": [
- {
- "name": "Catalyst Team",
- "url": "https://projectcatalyst.io/"
- }
- ],
- "properties": {
- "action": {
- "$ref": "#/definitions/action"
- }
- },
- "required": [
- "action"
- ],
- "title": "Proposal Submission Action Payload Schema",
- "type": "object",
- "x-changelog": {
- "2025-03-01": [
- "First Version Created."
- ]
- }
- }
+ "description": "JSON Document which must validate against the referenced template."
},
"signers": {
- "referenced": true,
"roles": {
"user": [
- "Proposer"
+ "Registered"
]
},
"update": {
- "author": true,
- "collaborators": true
+ "author": true
}
},
"type": [
- "5e60e623-ad02-4a1b-a1ac-406db978ee48",
- "7808d2ba-d511-40af-84e8-c0d1625fdfdc",
- "78927329-cfd9-4ea1-9c71-0e019b126a65"
+ "b679ded3-0e7c-41ba-89f8-da62a17898ea",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
],
- "validation": "No validation is required beyond as defined by:\n\n* [metadata](#metadata) \n* [payload](#payload)\n* [signers](#signers)",
+ "validation": "A comment which is a reply *MUST* reference the same document.\nIt may reference a different version of the document.",
"versions": [
{
"changes": "* First Published Version",
@@ -1926,9 +1935,9 @@
}
]
},
- "Proposal Template": {
+ "Proposal Comment Form Template": {
"authors": {},
- "description": "## Proposal Template Document\n\nA Proposal Template defines the allowed payload contents of a\nlinked proposal.\n\nProposals themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal is controlled by its template.",
+ "description": "A Proposal Comment Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Proposal Comment Form Template is a JSON Schema Document.\n\nProposal Comment entry *SHOULD* use the hints when collecting \ndata defined by the Proposal Comment Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Proposal Comment Presentation Template can be used to\nformat the Proposal Comment data for presentation.\n\nThe Proposal Comment Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Proposal Comment.\n\nThe payload of a Proposal Comment is controlled by its template.",
"headers": {
"content type": {
"coseLabel": 3,
@@ -1948,27 +1957,28 @@
}
},
"metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
"collaborators": {
"description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
"format": "Collaborators Reference List",
"required": "excluded",
"validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
},
"id": {
"description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
"format": "Document Id",
"required": "yes",
"validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
},
"parameters": {
"description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": [
- "template"
- ],
+ "linked_refs": null,
"multiple": false,
"required": "yes",
"type": [
@@ -1976,56 +1986,46 @@
"Campaign Parameters",
"Category Parameters"
],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
},
"ref": {
"description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
},
"reply": {
"description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
"format": "Document Reference",
"required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
},
"revocations": {
"description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
"format": "Version Revocations",
"required": "excluded",
"validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
"section": {
"description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
"format": "Section Reference",
"required": "excluded",
"validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
},
"template": {
"description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
"format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
- "type": "Proposal Meta Template",
+ "required": "excluded",
"validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
},
"type": {
"description": "The document TYPE.",
- "exclusive": null,
"format": "Document Type",
"required": "yes",
"validation": "**MUST** be a known document type."
},
"ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
"format": "Document Ver",
"required": "yes",
"validation": "The document version must always be >= the document ID."
@@ -2033,13 +2033,12 @@
},
"notes": [],
"payload": {
- "description": "JSON Schema document which defines the valid contents of a proposal document."
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nProposal Comment Document."
},
"signers": {
"roles": {
"admin": [
- "Brand Admin",
- "Campaign Admin"
+ "Brand Admin"
],
"user": []
},
@@ -2049,6 +2048,7 @@
},
"type": [
"0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "b679ded3-0e7c-41ba-89f8-da62a17898ea",
"7808d2ba-d511-40af-84e8-c0d1625fdfdc"
],
"versions": [
@@ -2061,214 +2061,2634 @@
"changes": "* Use generalized parameters.",
"modified": "2025-05-05",
"version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
}
]
- }
- },
- "documentationLinks": {
- "CBOR-TAG-37": "https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md",
- "CBOR-TAG-42": "https://github.com/ipld/cid-cbor/",
- "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode",
- "IPFS-CID": "https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid",
- "JSON Schema": "https://json-schema.org/draft-07",
- "RFC3629": "https://datatracker.ietf.org/doc/html/rfc3629",
- "RFC3986": "https://datatracker.ietf.org/doc/html/rfc3986",
- "RFC7932": "https://www.rfc-editor.org/rfc/rfc7932",
- "RFC8259": "https://www.rfc-editor.org/rfc/rfc8259.html",
- "RFC8610": "https://www.rfc-editor.org/rfc/rfc8610",
- "RFC8949": "https://www.rfc-editor.org/rfc/rfc8949.html",
- "RFC9052": "https://datatracker.ietf.org/doc/html/rfc9052",
- "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si",
- "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1",
- "RFC9165": "https://www.rfc-editor.org/rfc/rfc9165",
- "RFC9562": "https://www.rfc-editor.org/rfc/rfc9562.html",
- "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4",
- "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7",
- "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor",
- "application/json": "https://www.iana.org/assignments/media-types/application/json",
- "application/schema+json": "https://datatracker.ietf.org/doc/draft-bhutton-json-schema/",
- "br": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br"
- },
- "encodingTypes": {
- "br": {
- "description": "BROTLI Compression"
- }
- },
- "linkAKA": {
- "BROTLI": "RFC7932",
- "CBOR": "RFC8949",
- "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42",
- "CDDL": "RFC8610",
- "COSE": "RFC9052",
- "COSE Header Parameters": "RFC9052-HeaderParameters",
- "COSE Sign": "RFC9052-CoseSign",
- "IPFS CID": "IPFS-CID",
- "JSON": "RFC8259",
- "RFC9165 - CDDL Additional Controls": "RFC9165",
- "URI": "RFC3986",
- "UTF-8": "RFC3629",
- "UUID": "RFC9562",
- "UUIDv4": "RFC9562-V4",
- "UUIDv7": "RFC9562-V7"
- },
- "metadata": {
- "collaborators": {
- "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
- "exclusive": null,
- "format": "Collaborators Reference List",
- "required": "optional",
- "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
- },
- "id": {
- "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
- "exclusive": null,
- "format": "Document Id",
- "required": "yes",
- "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
- },
- "parameters": {
- "description": "A reference to the Parameters Document this document lies under.",
- "exclusive": null,
- "format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
- "type": [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters",
- "Decision Parameters"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document."
- },
- "ref": {
- "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
- "exclusive": null,
- "format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
- "type": [
- "Proposal Meta Template",
- "Proposal Template",
- "Proposal",
- "Proposal Comment Meta Template",
- "Proposal Comment Template",
- "Proposal Comment",
- "Proposal Submission Action",
- "Proposal Moderation Action",
- "Comment Moderation Action",
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters",
- "Decision Parameters"
- ],
- "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
- },
- "reply": {
- "description": "Reference to a Comment document type being referred to.",
- "exclusive": null,
- "format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
- "type": [
- "Proposal Comment"
- ],
- "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
- },
- "revocations": {
- "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
- "exclusive": null,
- "format": "Version Revocations",
- "required": "excluded",
- "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
},
- "section": {
- "description": "A Reference to the original document, or the comment being replied to.",
- "exclusive": null,
- "format": "Section Reference",
- "required": "optional",
- "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
- },
- "template": {
- "description": "Reference to the template used to create and/or validate this document.",
- "exclusive": null,
- "format": "Document Reference",
- "linked_refs": null,
- "multiple": false,
- "required": "optional",
+ "Proposal Comment Presentation Template": {
+ "authors": {},
+ "description": "A Proposal Comment Presentation Template defines how the data\ncaptured by the Proposal Comment Form Template is to be displayed.\n\nMultiple Proposal Comment Presentation Templates can exist for the \nsame Proposal Comment Form Template.\nEach can be used to display the form data under different \ncircumstances.\n\nProposal Comment Presentation Templates can reference any data contained\nin the Proposal Comment Document, as well as any documents linked by:\n\n* `ref`\n* `reply`\n* `parameters`\n\nThe presentation of the payload of a Proposal Comment is controlled by \nits Proposal Comment Presentation Template/s.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/schema+json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "TBD.\nBut roughly, will be:\n\n1. A way to identify where the presentation template is intended to be used.\n2. Optional CSS to control the presentation.\n3. A Handlebars templated HTML or Markdown file data which defines the presentation."
+ },
+ "signers": {
+ "roles": {
+ "admin": [
+ "Brand Admin",
+ "Campaign Admin"
+ ],
+ "user": []
+ },
+ "update": {
+ "author": true
+ }
+ },
"type": [
- "Proposal Meta Template",
- "Proposal Template",
- "Proposal Comment Meta Template",
- "Proposal Comment Template"
+ "cb99b9bd-681a-49d8-9836-89107c02e8ef",
+ "b679ded3-0e7c-41ba-89f8-da62a17898ea",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
],
- "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
- },
- "type": {
- "description": "The document TYPE.",
- "exclusive": null,
- "format": "Document Type",
- "required": "yes",
- "validation": "**MUST** be a known document type."
- },
- "ver": {
- "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`",
- "exclusive": null,
- "format": "Document Ver",
- "required": "yes",
- "validation": "The document version must always be >= the document ID."
- }
- },
- "metadataFormats": {
- "Collaborators Reference List": {
- "cddl": "collaborators",
- "description": "A list of collaborators who can participate in drafting and submitting a document"
- },
- "Document Id": {
- "cddl": "document_id",
- "description": "A unique document identifier"
- },
- "Document Reference": {
- "cddl": "document_ref",
- "description": "A document reference identifier"
- },
- "Document Type": {
- "cddl": "document_type",
- "description": "A document type identifier"
- },
- "Document Ver": {
- "cddl": "document_ver",
- "description": "A unique chronological document version"
- },
- "Section Reference": {
- "cddl": "section_ref",
- "description": "A document section reference identifier"
- },
- "UUIDv4": {
- "cddl": "uuid_v4",
- "description": "Version 4 formatted UUID"
- },
- "UUIDv7": {
- "cddl": "uuid_v7",
- "description": "Version 7 formatted UUID"
- },
- "Version Revocations": {
- "cddl": "revocations",
- "description": "A list of all versions of this document which are 'revoked'."
- }
- },
- "metadata_order": [
- "type",
- "id",
- "ver",
- "ref",
- "template",
- "reply",
- "section",
- "collaborators",
- "revocations",
- "parameters"
- ]
+ "versions": [
+ {
+ "changes": "* First Version.",
+ "modified": "2025-05-05",
+ "version": "0.04"
+ }
+ ]
+ },
+ "Proposal Form Template": {
+ "authors": {},
+ "description": "A Proposal Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Proposal Form Template is a JSON Schema Document.\n\nProposal entry *SHOULD* use the hints when collecting \ndata defined by the Proposal Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Proposal Presentation Template can be used to\nformat the Proposal data for presentation.\n\nThe Proposal Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Proposal.\n\nThe payload of a Proposal is controlled by its template.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/schema+json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nProposal Document."
+ },
+ "signers": {
+ "roles": {
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ ],
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-04-04",
+ "version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
+ }
+ ]
+ },
+ "Proposal Moderation Action": {
+ "authors": {},
+ "description": "A Moderation action performed on a Proposal.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Proposal",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "signers": {
+ "roles": {
+ "user": [
+ "Registered"
+ ]
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "5e60e623-ad02-4a1b-a1ac-406db978ee48",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc",
+ "a5d232b8-5e03-4117-9afd-be32b878fcdd"
+ ],
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-04-04",
+ "version": "0.01"
+ }
+ ]
+ },
+ "Proposal Presentation Template": {
+ "authors": {},
+ "description": "A Proposal Presentation Template defines how the data\ncaptured by the Proposal Form Template is to be displayed.\n\nMultiple Proposal Presentation Templates can exist for the \nsame Proposal Form Template.\nEach can be used to display the form data under different \ncircumstances.\n\nProposal Presentation Templates can reference any data contained\nin the Proposal Document, as well as any documents linked by:\n\n* `ref`\n* `reply`\n* `parameters`\n\nThe presentation of the payload of a Proposal is controlled by \nits Proposal Presentation Template/s.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/schema+json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "TBD.\nBut roughly, will be:\n\n1. A way to identify where the presentation template is intended to be used.\n2. Optional CSS to control the presentation.\n3. A Handlebars templated HTML or Markdown file data which defines the presentation."
+ },
+ "signers": {
+ "roles": {
+ "admin": [
+ "Brand Admin",
+ "Campaign Admin"
+ ],
+ "user": []
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "cb99b9bd-681a-49d8-9836-89107c02e8ef",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
+ ],
+ "versions": [
+ {
+ "changes": "* First Version.",
+ "modified": "2025-05-05",
+ "version": "0.04"
+ }
+ ]
+ },
+ "Proposal Submission Action": {
+ "authors": {},
+ "business_logic": {
+ "back_end": "A Submitted proposal with collaborators *MUST* have \na `final` submission by *ALL* listed `collaborators`.\nIf any `collaborator` has not submitted a `final` submission by the deadline, then the proposal \nis not considered `final` and will not be considered in the category it was being submitted to.",
+ "front_end": "A proposal with `collaborators` will not be shown as having a confirmed collaborator,\nunless there exists a `draft` or `final` proposal submission from that collaborator.\n\nAny document that lists a collaborator should be highlighted to that collaborator so\nthey can take appropriate action, such as:\n\n* Confirm they are a collaborator by submitting this document as `draft`\n* Agree to being a collaborator on the final submission by submitting this document as `final`\n* Hide themselves from the collaborators list but do not remove themselves by submitting `hide`\n* Remove themselves permanently as a collaborator by publishing a new version with them removed.\n\nTo eliminate the necessity for collaborators to accept collaboration on every version, \nthey will be considered as agreeing to be a collaborator on any version of the document\nthat lists them, if their latest submission is `draft` or `final`.\n\nIf their latest submission on a document is `hide` they should be considered to not\nhave agreed to be a collaborator.\n\n*NOTE* `final` status ONLY applies to the exactly referenced document and version."
+ },
+ "description": "Proposal Submission Action\n\nA Proposal Submission Action is a document which can attempt to either submit a \nparticular version of a proposal into a campaign, or withdraw it.\n\nThe last action on the document ts the action which takes effect at the deadline.\n\nFor multiple collaborators, multiple submission actions can be posted independently, \nbut none of them will take effect until ALL collaborators have posted equivalent actions.\n\nFor example, three collaborators Alice/Bob/Claire can each post one submission action\nfor the same document. \nUnless they all submit the same version of the proposal\nthe proposal will not be seen as submitted.\n\nThe payload is a fixed format.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": [
+ "ref"
+ ],
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": true,
+ "required": "yes",
+ "type": "Proposal",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "The kind of action is controlled by this payload.\nThe Payload is a JSON Document, and must conform to this schema.\n\nStates:\n\n* `final` : All collaborators must publish a `final` status for the proposal to be `final`.\n* `draft` : Reverses the previous `final` state for a signer and accepts collaborator status to a document. \n* `hide` : Requests the proposal be hidden (not final, but a hidden draft). \n\t\t\t`hide` is only actioned if sent by the author, \n\t\t\tfor a collaborator it identified that they do not wish to be listed as a `collaborator`.",
+ "examples": [
+ {
+ "description": "This document indicates the linked proposal is final and requested to proceed for further consideration.",
+ "example": {
+ "action": "final"
+ },
+ "title": "Final Proposal Submission"
+ },
+ {
+ "description": "This document indicates the linked proposal is no longer final and should not proceed for further consideration.\nIt is also used by collaborators to accept that they are a collaborator on a document.",
+ "example": {
+ "action": "draft"
+ },
+ "title": "Draft Proposal Submission"
+ },
+ {
+ "description": "If submitted by the proposal author the document is hidden, it is still public but not shown as\na proposal being drafted.\nIf submitted by a collaborator, that collaborator is declaring they do not wish to be listed as\na collaborator on the proposal.",
+ "example": {
+ "action": "hide"
+ },
+ "title": "Hidden Proposal Submission"
+ }
+ ],
+ "schema": {
+ "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "additionalProperties": false,
+ "definitions": {
+ "action": {
+ "description": "The action being performed on the Proposal.",
+ "enum": [
+ "final",
+ "draft",
+ "hide"
+ ],
+ "type": "string"
+ }
+ },
+ "description": "Structure of the payload of a Proposal Submission Action.",
+ "maintainers": [
+ {
+ "name": "Catalyst Team",
+ "url": "https://projectcatalyst.io/"
+ }
+ ],
+ "properties": {
+ "action": {
+ "$ref": "#/definitions/action"
+ }
+ },
+ "required": [
+ "action"
+ ],
+ "title": "Proposal Submission Action Payload Schema",
+ "type": "object",
+ "x-changelog": {
+ "2025-03-01": [
+ "First Version Created."
+ ]
+ }
+ }
+ },
+ "signers": {
+ "referenced": true,
+ "roles": {
+ "user": [
+ "Proposer"
+ ]
+ },
+ "update": {
+ "author": true,
+ "collaborators": true
+ }
+ },
+ "type": [
+ "5e60e623-ad02-4a1b-a1ac-406db978ee48",
+ "7808d2ba-d511-40af-84e8-c0d1625fdfdc",
+ "78927329-cfd9-4ea1-9c71-0e019b126a65"
+ ],
+ "validation": "No validation is required beyond as defined by:\n\n* [metadata](#metadata) \n* [payload](#payload)\n* [signers](#signers)",
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-04-04",
+ "version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
+ }
+ ]
+ },
+ "Rep Nomination": {
+ "authors": {
+ "Neil McAuliffe": "neil.mcauliffe@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "business_logic": {
+ "back_end": "* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.\n* The system will only consider Representatives as having valid Nominations if:\n * Their latest Nomination in a Contest is not Revoked.\n * Their latest Delegation in a Contest references their latest Nomination.",
+ "front_end": "* Allows a Representative to create or update their profile for a category.\n* The Representative sets their status to 'active' to be discoverable for delegation.\n* The Representative `revokes` the Nomination to signal they are no longer \n\tparticipating in the category.\n* Nominations are not valid if the latest Delegation by the Representative does NOT\n\treference their latest Nomination."
+ },
+ "description": "A Representative Nomination Document is created to opt\nin as a Representative Voter for a specific Contest on a Brand/Campaign or Category.\n\nThis Document is a kind of `Profile` that is primarily used to\nhelp justify the Representatives Nomination to prospective delegators.\n\nThe user must have registered as a Representative.\nThe presence of this document signifies the user's intent to participate in that \ncontest as a Representative.\n\nThe document's structure is defined by the associated \nRep Nomination Form Template.\nThis allows an Admin to specify contest-specific requirements.\n\nThe Representative can retract their nomination by using the `revoke` metadata to\nrevoke this Nomination document.\n\nIt is an extension of all other profiles attached to the same Catalyst ID.\n\nProfiles themselves are intentionally general, however they may be\nlinked to a Brand/Campaign/Category via the template used by the profile.\n\nThe payload of a profile is controlled by its template.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": [
+ "template"
+ ],
+ "multiple": false,
+ "required": "yes",
+ "type": "Contest Parameters",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Rep Profile",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "optional",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Rep Nomination Form Template",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "The Representative's profile data for a specific contest.\nIts structure is defined by the referenced template document.\n\nIn the case of Revoking a nomination the payload is `nil`."
+ },
+ "signers": {
+ "roles": {
+ "user": [
+ "Representative"
+ ]
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "bf9abd97-5d1f-4429-8e80-740fea371a9c",
+ "94579df1-a6dc-433b-a8e8-910c5dc2f0e3"
+ ],
+ "validation": "* The signer MUST be a registered 'Representative'.\n* The 'ref' metadata field MUST point to a valid 'Representative Profile' document.\n* The 'parameters' metadata field MUST point to a valid 'Contest Parameters' document.\n* The 'template' metadata field MUST point to a valid 'Representative Nomination Form Template' document.\n* The payload MUST be valid against the JSON schema defined in the referenced template.\n* Other rules may apply as defined by the Contest or other parameters which can\n\tcontrol who may validly nominate as a representative in a Contest.\n\nNo Nomination is valid unless the latest Contest Delegation of the Delegate\nrefers to their own Nomination.\nThis requires that Nominating is a two step process:\n\n1. Post the Nomination Document.\n2. Post a Contest Delegation delegating to the new Nomination Document.\n\nUpdating the Nomination Document will invalidate all Nominations to the \nRepresentative.\n\nThis is because Delegation points to a *SPECIFIC* Nomination, and it\n*MUST* be the latest for the Representative on the Contest.\nAs the Nomination contains information that the User relies on\nwhen choosing to delegate, changing that information could have a \nreal and detrimental result in the Delegation choice.\nTherefore, for a Delegation to be valid, it *MUST* point to the\nlatest Nomination for a Representative.",
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-06-19",
+ "version": "0.01"
+ }
+ ]
+ },
+ "Rep Nomination Form Template": {
+ "authors": {},
+ "description": "A Rep Nomination Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Rep Nomination Form Template is a JSON Schema Document.\n\nRep Nomination entry *SHOULD* use the hints when collecting \ndata defined by the Rep Nomination Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Rep Nomination Presentation Template can be used to\nformat the Rep Nomination data for presentation.\n\nThe Rep Nomination Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Rep Nomination.\n\nThe payload of a Rep Nomination is controlled by its template.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/schema+json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Contest Parameters",
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nRep Nomination Document."
+ },
+ "signers": {
+ "roles": {
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "bf9abd97-5d1f-4429-8e80-740fea371a9c",
+ "94579df1-a6dc-433b-a8e8-910c5dc2f0e3"
+ ],
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-04-04",
+ "version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
+ }
+ ]
+ },
+ "Rep Profile": {
+ "authors": {
+ "Neil McAuliffe": "neil.mcauliffe@iohk.io",
+ "Steven Johnson": "steven.johnson@iohk.io"
+ },
+ "business_logic": {
+ "back_end": "* Validate Representative profile data against the referenced 'Rep Profile Template' and store/index it.\n* This global profile is the foundational document referenced by all of the Rep's contest specific profiles.",
+ "front_end": "* Display and allow editing of the Representative's core profile fields.\n* This profile serves as the central hub for a Representative's public identity."
+ },
+ "description": "A Rep Profile allows a representative voter to publish information\nabout themselves to help explain who they are and why someone should\nconsider delegating to them.\n\nIt is an extension of all other profiles attached to the same Catalyst ID.\n\nProfiles themselves are intentionally general, however they may be\nlinked to a brand via the template used by the profile.\n\nThe payload of a profile is controlled by its template.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": [
+ "template"
+ ],
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "optional",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": "Rep Profile Form Template",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "The Representative profile payload contains all Representative-specific fields.\nIts structure is defined by the referenced Rep Profile Template.\n\nMust be valid according to the schema contained within the \n`Document Reference` from the `template` metadata."
+ },
+ "signers": {
+ "roles": {
+ "user": [
+ "Representative"
+ ]
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "0f2c86a2-ffda-40b0-ad38-23709e1c10b3",
+ "94579df1-a6dc-433b-a8e8-910c5dc2f0e3"
+ ],
+ "validation": "* The signer MUST be a registered 'Representative'.\n* The payload MUST be valid against the JSON schema defined in the referenced \n'Rep Profile Template'.",
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-06-19",
+ "version": "0.01"
+ }
+ ]
+ },
+ "Rep Profile Form Template": {
+ "authors": {},
+ "description": "A Rep Profile Form Template defines both:\n\n* The data that is entered in the Form.\n* Formatting hints for the collection of the data in a form.\n\nA Rep Profile Form Template is a JSON Schema Document.\n\nRep Profile entry *SHOULD* use the hints when collecting \ndata defined by the Rep Profile Form Template to provide a \nconsistent user interface.\nIt *CAN* also use those hints when re-displaying the full forms data.\n\nAlternatively a Rep Profile Presentation Template can be used to\nformat the Rep Profile data for presentation.\n\nThe Rep Profile Document is intentionally general, \nhowever it may be linked to a brand/campaign or category \nvia the template used by the Rep Profile.\n\nThe payload of a Rep Profile is controlled by its template.",
+ "headers": {
+ "content type": {
+ "coseLabel": 3,
+ "description": "Media Type/s allowed in the Payload",
+ "format": "Media Type",
+ "required": "yes",
+ "value": "application/schema+json"
+ },
+ "content-encoding": {
+ "coseLabel": "content-encoding",
+ "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.",
+ "format": "HTTP Content Encoding",
+ "required": "optional",
+ "value": [
+ "br"
+ ]
+ }
+ },
+ "metadata": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "excluded",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document."
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "excluded",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "yes",
+ "type": [
+ "Brand Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "excluded",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "required": "excluded",
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents new versions of the same document as it changes over time.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "notes": [],
+ "payload": {
+ "description": "JSON Schema document which defines the valid contents and \nformatting hints for the collection of data for a \nRep Profile Document."
+ },
+ "signers": {
+ "roles": {
+ "admin": [
+ "Brand Admin"
+ ],
+ "user": []
+ },
+ "update": {
+ "author": true
+ }
+ },
+ "type": [
+ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f",
+ "0f2c86a2-ffda-40b0-ad38-23709e1c10b3",
+ "94579df1-a6dc-433b-a8e8-910c5dc2f0e3"
+ ],
+ "versions": [
+ {
+ "changes": "* First Published Version",
+ "modified": "2025-04-04",
+ "version": "0.01"
+ },
+ {
+ "changes": "* Use generalized parameters.",
+ "modified": "2025-05-05",
+ "version": "0.03"
+ },
+ {
+ "changes": "* Generalize the Form Template definitions.",
+ "modified": "2025-05-05",
+ "version": "0.04"
+ }
+ ]
+ }
+ },
+ "documentation": {
+ "linkAKA": {
+ "BROTLI": "RFC7932",
+ "CBOR": "RFC8949",
+ "CBOR Deterministic Encoding": "CBOR-LFD-ENCODING",
+ "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42",
+ "CDDL": "RFC8610",
+ "COSE": "RFC9052",
+ "COSE Header Parameters": "RFC9052-HeaderParameters",
+ "COSE Sign": "RFC9052-CoseSign",
+ "HTML": "HTML5",
+ "IPFS CID": "IPFS-CID",
+ "JSON": "RFC8259",
+ "JSON Schema": "JSON Schema-2020-12",
+ "JSON Schema Draft 2020-12": "JSON Schema-2020-12",
+ "Markdown": "CommonMark",
+ "RFC9165 - CDDL Additional Controls": "RFC9165",
+ "URI": "RFC3986",
+ "UTF-8": "RFC3629",
+ "UUID": "RFC9562",
+ "UUIDv4": "RFC9562-V4",
+ "UUIDv7": "RFC9562-V7",
+ "application/cddl": "RFC8610",
+ "application/schema+json": "JSON Schema-2020-12",
+ "charset=utf-8": "RFC3629",
+ "charset=utf-8;": "RFC3629",
+ "template=handlebars": "Handlebars",
+ "text/css;": "text/css",
+ "text/html;": "HTML5",
+ "text/markdown;": "CommonMark",
+ "text/plain;": "text/plain"
+ },
+ "links": {
+ "CBOR-LFD-ENCODING": "https://www.rfc-editor.org/rfc/rfc8949.html#section-4.2.3",
+ "CBOR-TAG-37": "https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md",
+ "CBOR-TAG-42": "https://github.com/ipld/cid-cbor/",
+ "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode",
+ "CSS": "https://www.w3.org/Style/CSS/",
+ "CommonMark": "https://spec.commonmark.org/0.31.2/",
+ "HTML5": "https://html.spec.whatwg.org/multipage/syntax.html#syntax",
+ "Handlebars": "https://handlebarsjs.com/",
+ "IPFS-CID": "https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid",
+ "JSON Schema-2020-12": "https://json-schema.org/draft/2020-12",
+ "JSON Schema-draft7": "https://json-schema.org/draft-07",
+ "Mustache": "https://mustache.github.io/mustache.5.html",
+ "RFC3629": "https://datatracker.ietf.org/doc/html/rfc3629",
+ "RFC3986": "https://datatracker.ietf.org/doc/html/rfc3986",
+ "RFC7932": "https://www.rfc-editor.org/rfc/rfc7932",
+ "RFC8259": "https://www.rfc-editor.org/rfc/rfc8259.html",
+ "RFC8610": "https://www.rfc-editor.org/rfc/rfc8610",
+ "RFC8949": "https://www.rfc-editor.org/rfc/rfc8949.html",
+ "RFC9052": "https://datatracker.ietf.org/doc/html/rfc9052",
+ "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si",
+ "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1",
+ "RFC9165": "https://www.rfc-editor.org/rfc/rfc9165",
+ "RFC9562": "https://www.rfc-editor.org/rfc/rfc9562.html",
+ "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4",
+ "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7",
+ "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor",
+ "application/json": "https://www.iana.org/assignments/media-types/application/json",
+ "br": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br",
+ "text/css": "https://www.rfc-editor.org/rfc/rfc2318.html",
+ "text/plain": "https://www.rfc-editor.org/rfc/rfc2046.html"
+ }
+ },
+ "encodingTypes": {
+ "br": {
+ "description": "BROTLI Compression"
+ }
+ },
+ "formTemplate": {
+ "dropDownSingleSelect": {
+ "definition": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "description": "UI - Drop Down Selection of a single entry from the defined enum.\n\nSelect one option from a selector styled as a dropdown menu.\nOnly one choice is allowed.",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "enum": {
+ "description": "An array of string to select from.",
+ "items": {
+ "description": "An element of the Enum.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "multiLineTextEntry": {
+ "definition": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "description": "UI - One or more Lines of text entry.\nLine breaks, and special characters are allowed.\nSpecial formatted markup, such as Markdown are not allowed.\nEnter multiple lines of plain text. You can use line breaks but no special formatting.",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxLength": {
+ "description": "Maximum number of characters allowed in the field.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minLength": {
+ "description": "Minimum number of characters allowed in the field.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "multiLineTextEntryListMarkdown": {
+ "definition": {
+ "items": {
+ "contentMediaType": "text/markdown",
+ "minLength": 1,
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "description": "UI - A Growable List of markdown formatted text fields.\nEach entry is a multiline markdown formatted string.\nMarkdown Formatting, line breaks, or special characters are allowed.\nAdd multiple text entries.\nEach entry should be unique.",
+ "parameters": {
+ "contains": {
+ "description": "The choices the multi select can contain.",
+ "items": {
+ "description": "An individual Choice.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "default": {
+ "description": "Default Array of text can be supplied.",
+ "required": "optional",
+ "type": "string"
+ },
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxItems": {
+ "description": "An array instance is valid against \"maxItems\" if its size is less than, or equal to, the value of this keyword.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minItems": {
+ "description": "An array instance is valid against \"minItems\" if its size is greater than, or equal to, the value of this keyword.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "multiLineTextEntryMarkdown": {
+ "definition": {
+ "contentMediaType": "text/markdown",
+ "pattern": "^[\\S\\s]*$",
+ "type": "string"
+ },
+ "description": "UI - Multiline text entry with Markdown content.\nUse Markdown formatting for rich text. \nMarkdown formatting is as defined by CommonMark.\n\nThe following Markdown Extensions are also supported:\n\n* None",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxLength": {
+ "description": "Maximum number of characters allowed in the field.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minLength": {
+ "description": "Minimum number of characters allowed in the field.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "multiSelect": {
+ "definition": {
+ "items": {
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "description": "UI - Multiselect from the given items.\n\nSelect multiple options from the dropdown menu.\nMultiple choices are allowed.\nAll choices MUST be unique.",
+ "parameters": {
+ "contains": {
+ "description": "The choices the multi select can contain.",
+ "items": {
+ "description": "An individual Choice.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "default": {
+ "description": "Default selections can be supplied.",
+ "required": "optional",
+ "type": "string"
+ },
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxItems": {
+ "description": "An array instance is valid against \"maxItems\" if its size is less than, or equal to, the value of this keyword.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minItems": {
+ "description": "An array instance is valid against \"minItems\" if its size is greater than, or equal to, the value of this keyword.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "radioButtonSelect": {
+ "definition": {
+ "contentMediaType": "text/plain",
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "description": "UI - Radio Button Selection.\n\nSelect one option from a list of text options.\nSelector is styled as a set of Radio Buttons.",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "enum": {
+ "description": "An array of string to select from.",
+ "items": {
+ "description": "An element of the Enum.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "schemaReferenceNonUI": {
+ "definition": {
+ "readOnly": true,
+ "type": "string"
+ },
+ "description": "Enforces the json document having a proper reference to the schema.",
+ "parameters": {
+ "const": {
+ "description": "The path must always be this value. **MUST** match `default`.",
+ "required": "yes",
+ "type": "string"
+ },
+ "default": {
+ "description": "The path that is defined to find the matching json schema.",
+ "required": "yes",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "section": {
+ "definition": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "description": "UI - Logical Document Sub-Section Break.\nSubsections containing specific details about the proposal.",
+ "parameters": {
+ "description": {
+ "description": "The displayable description attached to the section. Markdown formatted contents.",
+ "required": "optional",
+ "type": "string"
+ },
+ "properties": {
+ "description": "The sub fields of the section.",
+ "required": "yes",
+ "type": "string"
+ },
+ "required": {
+ "description": "Which fields MUST appear in the segment.",
+ "required": "optional",
+ "type": "string"
+ },
+ "title": {
+ "description": "The title of the section.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-icon": {
+ "choices": [
+ "'all spaces menu'",
+ "'all spaces menu-1'",
+ "academic-cap",
+ "ada",
+ "adjustments",
+ "annotation",
+ "archive",
+ "arrow-circle-down",
+ "arrow-circle-left",
+ "arrow-circle-right",
+ "arrow-circle-up",
+ "arrow-down",
+ "arrow-left",
+ "arrow-narrow-down",
+ "arrow-narrow-left",
+ "arrow-narrow-right",
+ "arrow-narrow-up",
+ "arrow-right",
+ "arrow-triangle-down",
+ "arrow-triangle-up",
+ "arrow-up",
+ "arrows-expand",
+ "at-symbol",
+ "avatar_placeholder",
+ "backspace",
+ "badge-check",
+ "ban",
+ "beaker",
+ "bell",
+ "book-open",
+ "bookmark",
+ "bookmark-alt",
+ "bottom-main-content",
+ "bottom-rail-toggle",
+ "bottom-rail-toggle-1",
+ "briefcase",
+ "cake",
+ "calculator",
+ "calendar",
+ "camera",
+ "cash",
+ "chart-bar",
+ "chart-pie",
+ "chart-square-bar",
+ "chat",
+ "chat-alt",
+ "chat-alt-2",
+ "check",
+ "check-circle",
+ "chevron-double-down",
+ "chevron-double-left",
+ "chevron-double-right",
+ "chevron-double-up",
+ "chevron-down",
+ "chevron-down-1",
+ "chevron-left",
+ "chevron-right",
+ "chevron-up",
+ "chip",
+ "clipboard",
+ "clipboard-check",
+ "clipboard-copy",
+ "clipboard-list",
+ "clock",
+ "cloud",
+ "cloud-download",
+ "cloud-upload",
+ "code",
+ "cog-gear",
+ "collection",
+ "color-swatch",
+ "credit-card",
+ "cube",
+ "cube-transparent",
+ "currency-bangladeshi",
+ "currency-dollar",
+ "currency-euro",
+ "currency-pound",
+ "currency-rupee",
+ "currency-yen",
+ "cursor-click",
+ "curved-arrow-right",
+ "database",
+ "desktop-computer",
+ "device-mobile",
+ "device-tablet",
+ "document",
+ "document-add",
+ "document-remove",
+ "document-report",
+ "document-search",
+ "document-text",
+ "dots-circle-horizontal",
+ "dots-horizontal",
+ "dots-vertical",
+ "double_check",
+ "download",
+ "duplicate",
+ "emoji-happy",
+ "emoji-sad",
+ "exclamation",
+ "exclamation-circle",
+ "external-link",
+ "eye",
+ "eye-off",
+ "facebook",
+ "fast-forward",
+ "film",
+ "filter",
+ "finger-print",
+ "fire",
+ "flag",
+ "folder",
+ "folder-add",
+ "folder-download",
+ "folder-open",
+ "folder-remove",
+ "fund",
+ "gift",
+ "globe",
+ "globe-alt",
+ "hand",
+ "hashtag",
+ "heart",
+ "home",
+ "icon-user-remove",
+ "identification",
+ "inbox",
+ "inbox-in",
+ "information-circle",
+ "key",
+ "left-rail-toggle",
+ "library",
+ "light-bulb",
+ "lightning-bolt",
+ "link",
+ "linkedin",
+ "location-marker",
+ "lock-closed",
+ "lock-open",
+ "logout",
+ "logout-1",
+ "mail",
+ "mail-open",
+ "map",
+ "maximize-toggle",
+ "menu",
+ "menu-alt-1",
+ "menu-alt-2",
+ "menu-alt-3",
+ "menu-alt-4",
+ "microphone",
+ "minimize-toggle",
+ "minus",
+ "minus-circle",
+ "moon",
+ "move-item",
+ "music-note",
+ "newspaper",
+ "node-closed",
+ "node-line",
+ "node-line-end",
+ "node-open",
+ "office-building",
+ "paper-airplane",
+ "paper-clip",
+ "pause",
+ "pencil",
+ "pencil-alt",
+ "phone",
+ "phone-incoming",
+ "phone-missed-call",
+ "phone-outgoing",
+ "photograph",
+ "play",
+ "plus",
+ "plus_circle_filled",
+ "plus_circle_outlined",
+ "presentation-chart-bar",
+ "presentation-chart-line",
+ "printer",
+ "progress-track-warning",
+ "puzzle",
+ "qrcode",
+ "question-mark-circle",
+ "receipt-refund",
+ "receipt-tax",
+ "reddit",
+ "refresh",
+ "reply",
+ "rewind",
+ "right-rail-toggle",
+ "rss",
+ "rt_bold",
+ "rt_decrease_indent",
+ "rt_heading",
+ "rt_increase_indent",
+ "rt_italic",
+ "rt_ordered_list",
+ "rt_unordered_list",
+ "save",
+ "save-as",
+ "scale",
+ "scissors",
+ "search",
+ "search-circle",
+ "selector",
+ "send-airplane",
+ "server",
+ "share",
+ "shield-check",
+ "shield-exclamation",
+ "shopping-bag",
+ "shopping-cart",
+ "sm-view-grid-add",
+ "sort-ascending",
+ "sort-descending",
+ "sparkles",
+ "speakerphone",
+ "star_filled",
+ "star_outlined",
+ "status-offline",
+ "status-online",
+ "stop",
+ "summary",
+ "sun",
+ "support",
+ "switch-horizontal",
+ "switch-vertical",
+ "table",
+ "tag",
+ "template",
+ "terminal",
+ "thumb-down",
+ "thumb-up",
+ "ticket",
+ "top-bar",
+ "top-bar-filled",
+ "translate",
+ "trash",
+ "trending-down",
+ "trending-up",
+ "truck",
+ "unlink",
+ "upload",
+ "user",
+ "user-add",
+ "user-circle",
+ "user-group",
+ "users",
+ "variable",
+ "video-camera",
+ "view-boards",
+ "view-grid",
+ "view-list",
+ "volume-off",
+ "volume-up",
+ "vote",
+ "wallet",
+ "wifi",
+ "x",
+ "x-circle",
+ "xTwitter",
+ "zoom-in",
+ "zoom-out"
+ ],
+ "description": "The name of the Icon to display with the field.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-order": {
+ "description": "The ordering of the properties to be enforced when displayed.\nAny field not listed here will get displayed in an arbitrary order.",
+ "required": "yes",
+ "type": "string"
+ }
+ },
+ "parent": "segment"
+ },
+ "segment": {
+ "definition": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "description": "Logical Document Section - Grouping Only - Highest Level Group\n\"x-note\": \"\n\tMajor sections of the proposal. Each segment contains sections of information grouped together.\n\t\"",
+ "parameters": {
+ "description": {
+ "description": "The displayable description attached to the segment. Markdown formatted contents.",
+ "required": "optional",
+ "type": "string"
+ },
+ "properties": {
+ "description": "The sub fields of the segment.",
+ "required": "yes",
+ "type": "string"
+ },
+ "required": {
+ "description": "Which fields MUST appear in the segment.",
+ "required": "optional",
+ "type": "string"
+ },
+ "title": {
+ "description": "The title of the segment.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-icon": {
+ "choices": [
+ "'all spaces menu'",
+ "'all spaces menu-1'",
+ "academic-cap",
+ "ada",
+ "adjustments",
+ "annotation",
+ "archive",
+ "arrow-circle-down",
+ "arrow-circle-left",
+ "arrow-circle-right",
+ "arrow-circle-up",
+ "arrow-down",
+ "arrow-left",
+ "arrow-narrow-down",
+ "arrow-narrow-left",
+ "arrow-narrow-right",
+ "arrow-narrow-up",
+ "arrow-right",
+ "arrow-triangle-down",
+ "arrow-triangle-up",
+ "arrow-up",
+ "arrows-expand",
+ "at-symbol",
+ "avatar_placeholder",
+ "backspace",
+ "badge-check",
+ "ban",
+ "beaker",
+ "bell",
+ "book-open",
+ "bookmark",
+ "bookmark-alt",
+ "bottom-main-content",
+ "bottom-rail-toggle",
+ "bottom-rail-toggle-1",
+ "briefcase",
+ "cake",
+ "calculator",
+ "calendar",
+ "camera",
+ "cash",
+ "chart-bar",
+ "chart-pie",
+ "chart-square-bar",
+ "chat",
+ "chat-alt",
+ "chat-alt-2",
+ "check",
+ "check-circle",
+ "chevron-double-down",
+ "chevron-double-left",
+ "chevron-double-right",
+ "chevron-double-up",
+ "chevron-down",
+ "chevron-down-1",
+ "chevron-left",
+ "chevron-right",
+ "chevron-up",
+ "chip",
+ "clipboard",
+ "clipboard-check",
+ "clipboard-copy",
+ "clipboard-list",
+ "clock",
+ "cloud",
+ "cloud-download",
+ "cloud-upload",
+ "code",
+ "cog-gear",
+ "collection",
+ "color-swatch",
+ "credit-card",
+ "cube",
+ "cube-transparent",
+ "currency-bangladeshi",
+ "currency-dollar",
+ "currency-euro",
+ "currency-pound",
+ "currency-rupee",
+ "currency-yen",
+ "cursor-click",
+ "curved-arrow-right",
+ "database",
+ "desktop-computer",
+ "device-mobile",
+ "device-tablet",
+ "document",
+ "document-add",
+ "document-remove",
+ "document-report",
+ "document-search",
+ "document-text",
+ "dots-circle-horizontal",
+ "dots-horizontal",
+ "dots-vertical",
+ "double_check",
+ "download",
+ "duplicate",
+ "emoji-happy",
+ "emoji-sad",
+ "exclamation",
+ "exclamation-circle",
+ "external-link",
+ "eye",
+ "eye-off",
+ "facebook",
+ "fast-forward",
+ "film",
+ "filter",
+ "finger-print",
+ "fire",
+ "flag",
+ "folder",
+ "folder-add",
+ "folder-download",
+ "folder-open",
+ "folder-remove",
+ "fund",
+ "gift",
+ "globe",
+ "globe-alt",
+ "hand",
+ "hashtag",
+ "heart",
+ "home",
+ "icon-user-remove",
+ "identification",
+ "inbox",
+ "inbox-in",
+ "information-circle",
+ "key",
+ "left-rail-toggle",
+ "library",
+ "light-bulb",
+ "lightning-bolt",
+ "link",
+ "linkedin",
+ "location-marker",
+ "lock-closed",
+ "lock-open",
+ "logout",
+ "logout-1",
+ "mail",
+ "mail-open",
+ "map",
+ "maximize-toggle",
+ "menu",
+ "menu-alt-1",
+ "menu-alt-2",
+ "menu-alt-3",
+ "menu-alt-4",
+ "microphone",
+ "minimize-toggle",
+ "minus",
+ "minus-circle",
+ "moon",
+ "move-item",
+ "music-note",
+ "newspaper",
+ "node-closed",
+ "node-line",
+ "node-line-end",
+ "node-open",
+ "office-building",
+ "paper-airplane",
+ "paper-clip",
+ "pause",
+ "pencil",
+ "pencil-alt",
+ "phone",
+ "phone-incoming",
+ "phone-missed-call",
+ "phone-outgoing",
+ "photograph",
+ "play",
+ "plus",
+ "plus_circle_filled",
+ "plus_circle_outlined",
+ "presentation-chart-bar",
+ "presentation-chart-line",
+ "printer",
+ "progress-track-warning",
+ "puzzle",
+ "qrcode",
+ "question-mark-circle",
+ "receipt-refund",
+ "receipt-tax",
+ "reddit",
+ "refresh",
+ "reply",
+ "rewind",
+ "right-rail-toggle",
+ "rss",
+ "rt_bold",
+ "rt_decrease_indent",
+ "rt_heading",
+ "rt_increase_indent",
+ "rt_italic",
+ "rt_ordered_list",
+ "rt_unordered_list",
+ "save",
+ "save-as",
+ "scale",
+ "scissors",
+ "search",
+ "search-circle",
+ "selector",
+ "send-airplane",
+ "server",
+ "share",
+ "shield-check",
+ "shield-exclamation",
+ "shopping-bag",
+ "shopping-cart",
+ "sm-view-grid-add",
+ "sort-ascending",
+ "sort-descending",
+ "sparkles",
+ "speakerphone",
+ "star_filled",
+ "star_outlined",
+ "status-offline",
+ "status-online",
+ "stop",
+ "summary",
+ "sun",
+ "support",
+ "switch-horizontal",
+ "switch-vertical",
+ "table",
+ "tag",
+ "template",
+ "terminal",
+ "thumb-down",
+ "thumb-up",
+ "ticket",
+ "top-bar",
+ "top-bar-filled",
+ "translate",
+ "trash",
+ "trending-down",
+ "trending-up",
+ "truck",
+ "unlink",
+ "upload",
+ "user",
+ "user-add",
+ "user-circle",
+ "user-group",
+ "users",
+ "variable",
+ "video-camera",
+ "view-boards",
+ "view-grid",
+ "view-list",
+ "volume-off",
+ "volume-up",
+ "vote",
+ "wallet",
+ "wifi",
+ "x",
+ "x-circle",
+ "xTwitter",
+ "zoom-in",
+ "zoom-out"
+ ],
+ "description": "The name of the Icon to display with the field.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-order": {
+ "description": "The ordering of the properties to be enforced when displayed.\nAny field not listed here will get displayed in an arbitrary order.",
+ "required": "yes",
+ "type": "string"
+ }
+ },
+ "parent": "{}"
+ },
+ "singleGroupedTagSelector": {
+ "definition": {
+ "additionalProperties": false,
+ "required": [
+ "group",
+ "tag"
+ ],
+ "type": "object"
+ },
+ "description": "UI - A selector where a top level group selection, allows a single choice from a list of tags.\nSelect one option from the dropdown menu. \nOnly one choice is allowed.\n\nThe contents of the `singleGroupedTagSelector` *MUST* have the following format:\n\n```json\n\"oneOf\": [\n\t{\n\t\t\"properties\": {\n\t\t\t\"group\": {\n\t\t\t\t\"$ref\": \"#/definitions/tagGroup\",\n\t\t\t\t\"const\": \"Governance\"\n\t\t\t},\n\t\t\t\"tag\": {\n\t\t\t\t\"$ref\": \"#/definitions/tagSelection\",\n\t\t\t\t\"enum\": [\n\t\t\t\t\t\"Governance\",\n\t\t\t\t\t\"DAO\"\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t},\n```",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "oneOf_groupedTags": {
+ "description": "A set of tags with a group selector.",
+ "items": {
+ "description": "\tAn array of grouped tag objects, of which one can be selected.\n\tEach object *MUST* have the form:\n\t\n\t```json\n\t\"properties\": {\n\t\t\"group\": {\n\t\t\t\"$ref\": \"#/definitions/tagGroup\",\n\t\t\t\"const\": \n\t\t},\n\t\t\"tag\": {\n\t\t\t\"$ref\": \"#/definitions/tagSelection\",\n\t\t\t\"enum\": [\n\t\t\t\t,\n\t\t\t\t,\n\t\t\t\t...\n\t\t\t]\n\t\t}\n\t}\n\t```",
+ "required": "excluded",
+ "type": "object"
+ },
+ "property": "oneOf",
+ "required": "excluded",
+ "type": "array"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "singleLineHttpsURLEntry": {
+ "definition": {
+ "format": "uri",
+ "pattern": "^https://[^\\s]+$",
+ "type": "string"
+ },
+ "description": "UI - Single Line text entry for HTTPS Urls.\n\"x-note\": \n\tMust start with 'https://' and is followed by one or more \n\tnon-whitespace characters, ending at the end of the string.\n\t",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxLength": {
+ "description": "Maximum number of characters allowed in the field.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minLength": {
+ "description": "Minimum number of characters allowed in the field.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "singleLineHttpsURLEntryList": {
+ "definition": {
+ "items": {
+ "format": "uri",
+ "minLength": 1,
+ "pattern": "^https://[^\\s]+$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "description": "UI - A Growable List of single line text\nA single line of text.\nNo formatting, markup, line breaks, or special characters are allowed.\nAdd multiple single-line text entries.\nEach entry should be unique.",
+ "parameters": {
+ "contains": {
+ "description": "The choices the multi select can contain.",
+ "items": {
+ "description": "An individual Choice.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "default": {
+ "description": "Default Array of URLs can be supplied.",
+ "required": "optional",
+ "type": "string"
+ },
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxItems": {
+ "description": "An array instance is valid against \"maxItems\" if its size is less than, or equal to, the value of this keyword.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minItems": {
+ "description": "An array instance is valid against \"minItems\" if its size is greater than, or equal to, the value of this keyword.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "singleLineTextEntry": {
+ "definition": {
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "description": "UI - Single Line text entry without any markup or rich text capability.\nA single line of text.\nNo formatting, markup, line breaks, or special characters are allowed.",
+ "parameters": {
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxLength": {
+ "description": "Maximum number of characters allowed in the field.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minLength": {
+ "description": "Minimum number of characters allowed in the field.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ },
+ "singleLineTextEntryList": {
+ "definition": {
+ "items": {
+ "minLength": 1,
+ "pattern": "^[^\\n]*$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "description": "UI - A Growable List of single line text\nA single line of text.\nNo formatting, markup, line breaks, or special characters are allowed.\nAdd multiple single-line text entries.\nEach entry should be unique.",
+ "parameters": {
+ "contains": {
+ "description": "The choices the multi select can contain.",
+ "items": {
+ "description": "An individual Choice.",
+ "required": "excluded",
+ "type": "string"
+ },
+ "required": "yes",
+ "type": "array"
+ },
+ "default": {
+ "description": "Default Array of text can be supplied.",
+ "required": "optional",
+ "type": "string"
+ },
+ "description": {
+ "description": "The description of the field presented during data entry.",
+ "required": "optional",
+ "type": "string"
+ },
+ "maxItems": {
+ "description": "An array instance is valid against \"maxItems\" if its size is less than, or equal to, the value of this keyword.",
+ "required": "yes",
+ "type": "integer"
+ },
+ "minItems": {
+ "description": "An array instance is valid against \"minItems\" if its size is greater than, or equal to, the value of this keyword.",
+ "required": "optional",
+ "type": "integer"
+ },
+ "title": {
+ "description": "The label attached to the field.",
+ "required": "yes",
+ "type": "string"
+ },
+ "x-guidance": {
+ "description": "Long form Markdown formatted description to give guidance about how the field is to be completed.",
+ "required": "optional",
+ "type": "string"
+ },
+ "x-placeholder": {
+ "description": "Placeholder text to display inside the field if it is empty.",
+ "required": "optional",
+ "type": "string"
+ }
+ },
+ "parent": "section"
+ }
+ },
+ "metadata": {
+ "formats": {
+ "Chain Link": {
+ "cddl": "chain",
+ "description": "A link to a previous document in a chained sequence."
+ },
+ "Collaborators Reference List": {
+ "cddl": "collaborators",
+ "description": "A list of collaborators who can participate in drafting and submitting a document"
+ },
+ "Document Id": {
+ "cddl": "document_id",
+ "description": "A unique document identifier"
+ },
+ "Document Reference": {
+ "cddl": "document_refs",
+ "description": "A document reference identifier"
+ },
+ "Document Type": {
+ "cddl": "document_type",
+ "description": "A document type identifier"
+ },
+ "Document Ver": {
+ "cddl": "document_ver",
+ "description": "A unique chronological document version"
+ },
+ "Section Reference": {
+ "cddl": "section_ref",
+ "description": "A document section reference identifier"
+ },
+ "UUIDv4": {
+ "cddl": "uuid_v4",
+ "description": "Version 4 formatted UUID"
+ },
+ "UUIDv7": {
+ "cddl": "uuid_v7",
+ "description": "Version 7 formatted UUID"
+ },
+ "Version Revocations": {
+ "cddl": "revocations",
+ "description": "A list of all versions of this document which are 'revoked'."
+ }
+ },
+ "headers": {
+ "chain": {
+ "description": "An immutable link to the previous document in a chained sequence of documents.\nBecause ID/Ver only defines values for the current document, and is not intended \nby itself to prevent insertion of documents in a sequence, the `chain`\nmetadata allows for the latest document to directly point to its previous iteration.\n\nIt also aids in discoverability, where the latest document may be pinned but prior\ndocuments can be discovered automatically by following the chain.",
+ "format": "Chain Link",
+ "required": "optional",
+ "validation": "Chained Documents do not support collaborators.\nAny document which is attempted to be published in the sequence\nwhich is *NOT* published by the author of the first document in the\nsequence is fraudulent, and to be discarded.\n\nIn addition, the chained document *MUST*:\n\n* Not have `collaborators`;\n* Have the same `id` as the document being chained to;\n* Have a `ver` that is greater than the `ver` being chained to;\n* Have the same `type` as the chained document;\n* Have `parameters` match;\n* Have not be chaining to a document already chained to by another document;\n* Have its absolute `height` exactly one more than the `height` of the document being chained to.\n\nIF any of these validations fail, then the entire sequence of documents is INVALID.\nNot just the current document.\n\n##### Example of a Valid Chain\n\n\n``` mermaid\nclassDiagram\n direction LR\n class Last {\n type: \"=Intermediate.Document Type\"\n id: \"=Intermediate.Document ID\"\n ver: \">Intermediate.Document ID\"\n parameters: \"=Intermediate.Document Parameters\"\n chain.height: -2\n chain.document_ref: \"=Intermediate\"\n\n author(Intermediate.Catalyst ID)\n }\n style Last stroke:#060,stroke-width:4px\n\n class Intermediate {\n type: \"=First.Document Type\"\n id: \"=First.Document ID\"\n ver: \">First.Document ID\"\n parameters: \"=First.Document Parameters\"\n chain.height: 1\n chain.document_ref: \"=First\"\n\n author(First.Catalyst ID)\n }\n style Intermediate stroke:#060,stroke-width:4px\n\n class First {\n type: \"Document Type\"\n id: \"Document ID\"\n ver: \"=Document ID\"\n parameters: \"Document Parameters\"\n chain.height: 0\n chain.document_ref: None\n\n author(Catalyst ID)\n }\n style First stroke:#060,stroke-width:4px\n\n Last --|> Intermediate : chains to\n Intermediate --|> First : chains to\n\n\n```\n\n\n##### Example of an Invalid Chain\n\nEither of the two documents being present invalidates the data\nin the entire chain,\nas they are signed by the author of the chain.\n\n\n``` mermaid\nclassDiagram\n direction LR\n\n class Last {\n type: \"=Intermediate.Document Type\"\n id: \"=Intermediate.Document ID\"\n ver: \">Intermediate.Document ID\"\n parameters: \"=Intermediate.Document Parameters\"\n chain.height: -2\n chain.document_ref: \"=Intermediate\"\n\n author(Intermediate.Catalyst ID)\n }\n style Last stroke:#f60,stroke-width:4px\n\n class Intermediate {\n type: \"=First.Document Type\"\n id: \"=First.Document ID\"\n ver: \">First.Document ID\"\n parameters: \"=First.Document Parameters\"\n chain.height: 1\n chain.document_ref: \"=First\"\n\n author(First.Catalyst ID)\n }\n style Intermediate stroke:#f60,stroke-width:4px\n\n class First {\n type: \"Document Type\"\n id: \"Document ID\"\n ver: \"=Document ID\"\n parameters: \"Document Parameters\"\n chain.height: 0\n chain.document_ref: None\n\n author(Catalyst ID)\n }\n style First stroke:#f60,stroke-width:4px\n\n Last --|> Intermediate : chains to\n Intermediate --|> First : chains to\n\n class Invalid_Chain {\n type: \"=First.Document Type\"\n id: \"=First.Document ID\"\n ver: \">Intermediate.Document ID\"\n parameters: \"=First.Document Parameters\"\n chain.height: 1\n chain.document_ref: \"=First\"\n\n author(First.Catalyst ID)\n }\n\n Invalid_Chain --|> First : Invalidly chains to\n style Invalid_Chain fill:#100,stroke:#f00,stroke-width:4px\n\n\n class After_Final {\n type: \"=Final.Document Type\"\n id: \"=Final.Document ID\"\n ver: \">Final.Document ID\"\n parameters: \"=Final.Document Parameters\"\n chain.height: 3\n chain.document_ref: \"=Last\"\n\n author(Last.Catalyst ID)\n }\n\n After_Final --|> Last : Invalidly chains to\n style After_Final fill:#100,stroke:#f00,stroke-width:4px\n\n```\n\n\n##### Example of a Fraudulent Chain Document\n\nThe invalid document does not invalidate the chain,\nas its not signed by the author of the chained documents.\n\n\n``` mermaid\nclassDiagram\n direction LR\n class Last {\n type: \"=Intermediate.Document Type\"\n id: \"=Intermediate.Document ID\"\n ver: \">Intermediate.Document ID\"\n parameters: \"=Intermediate.Document Parameters\"\n chain.height: -2\n chain.document_ref: \"=Intermediate\"\n\n author(Intermediate.Catalyst ID)\n }\n style Last stroke:#060,stroke-width:4px\n\n class Intermediate {\n type: \"=First.Document Type\"\n id: \"=First.Document ID\"\n ver: \">First.Document ID\"\n parameters: \"=First.Document Parameters\"\n chain.height: 1\n chain.document_ref: \"=First\"\n\n author(First.Catalyst ID)\n }\n style Intermediate stroke:#060,stroke-width:4px\n\n class First {\n type: \"Document Type\"\n id: \"Document ID\"\n ver: \"=Document ID\"\n parameters: \"Document Parameters\"\n chain.height: 0\n chain.document_ref: None\n\n author(Catalyst ID)\n }\n style First stroke:#060,stroke-width:4px\n\n Last --|> Intermediate : chains to\n Intermediate --|> First : chains to\n\n class Rejected {\n type: \"=First.Document Type\"\n id: \"=First.Document ID\"\n ver: \">Intermediate.Document ID\"\n parameters: \"=Intermediate.Document Parameters\"\n chain.height: 1\n chain.document_ref: \"=First\"\n\n author(Other.Catalyst ID)\n }\n\n Rejected --|> Intermediate : Invalidly chains to\n style Rejected fill:#100,stroke:#f00,stroke-width:4px \n\n```\n"
+ },
+ "collaborators": {
+ "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.",
+ "format": "Collaborators Reference List",
+ "required": "optional",
+ "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author."
+ },
+ "id": {
+ "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.",
+ "format": "Document Id",
+ "required": "yes",
+ "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist."
+ },
+ "parameters": {
+ "description": "A reference to the Parameters Document this document lies under.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "optional",
+ "type": [
+ "Brand Parameters",
+ "Campaign Parameters",
+ "Category Parameters",
+ "Contest Parameters"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields: \n\n* Any linked referenced document that includes a `parameters` metadata must match the \n`parameters` of the referencing document,\nor a parent of those `parameters`.\n\nFor example, a linked reference to `Contest Parameters` is transitively a reference to\nthe Parameters document it references, and each parameters document they reference \nuntil the `Brand` parameters document is reached.\n\nThe use case here is for Templates.\nThe profile template, or proposal templates could be defined at any of these\nlevels, and as long as they all refer to the same chain of parameters in the\nhierarchy they are all valid."
+ },
+ "ref": {
+ "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nIf a reference is defined as required, there must be at least 1 reference specified.\nSome documents allow multiple references, and they are documented as required.\n\nThe document reference serves two purposes:\n \n1. It ensures that the document referenced by an ID/Version is not substituted.\n\tIn other words, that the document intended to be referenced, is actually referenced.\n2. It Allows the document to be unambiguously located in decentralized storage systems.\n\nThere can be any number of Document Locations in any reference.\nThe currently defined locations are:\n\n* `cid` : A CBOR Encoded IPLD Content Identifier ( AKA an IPFS CID ).\n* Others may be added when further storage mechanisms are defined.\n\nThe document location does not guarantee that the document is actually stored.\nIt only defines that if it were stored, this is the identifier\nthat is required to retrieve it.\nTherefore it is required that Document References\nare unique and reproducible, given a documents contents.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "optional",
+ "type": [
+ "Proposal Form Template",
+ "Proposal Presentation Template",
+ "Proposal",
+ "Proposal Comment Form Template",
+ "Proposal Comment Presentation Template",
+ "Proposal Comment",
+ "Proposal Submission Action",
+ "Proposal Moderation Action",
+ "Comment Moderation Action",
+ "Brand Parameters",
+ "Brand Parameters Form Template",
+ "Campaign Parameters",
+ "Campaign Parameters Form Template",
+ "Category Parameters",
+ "Category Parameters Form Template",
+ "Contest Parameters",
+ "Contest Parameters Form Template",
+ "Rep Profile",
+ "Rep Profile Form Template",
+ "Rep Nomination",
+ "Rep Nomination Form Template",
+ "Contest Delegation"
+ ],
+ "validation": "The following must be true for a valid reference:\n\n* The Referenced Document **MUST** Exist\n* Every value in the `document_locator` must consistently reference the exact same document.\n* The `document_id` and `document_ver` **MUST** match the values in the referenced document."
+ },
+ "reply": {
+ "description": "Reference to a Comment document type being referred to.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "optional",
+ "type": [
+ "Proposal Comment"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe `ref` of the `reply` document must be the same as\nthe original comment document."
+ },
+ "revocations": {
+ "description": "A document may include a list of any prior versions which are considered to be revoked.\nOnly the revocation list in the latest version of the document applies.\nRevoked documents are flagged as no longer valid, and should not be displayed.\nAs a special case, if the revocations are set to `true` then all versions of the document\nare revoked, including the latest document.\n\nIn this case, when the latest document is revoked, the payload may be empty.\nAny older document that has `revocations` set to `true` is always to be filtered\nand its payload is to be assumed to be invalid.\n\nThis allows for an entire document and any/all published versions to be revoked.\nA new version of the document that is published after this, may reinstate prior\ndocument versions, by not listing them as revoked. \nHowever, any document where revocations was set `true` can never be reinstated.",
+ "format": "Version Revocations",
+ "required": "excluded",
+ "validation": "If the field is `true` the payload may be absent or invalid.\nSuch documents may never be submitted."
+ },
+ "section": {
+ "description": "A Reference to the original document, or the comment being replied to.",
+ "format": "Section Reference",
+ "required": "optional",
+ "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to."
+ },
+ "template": {
+ "description": "Reference to the template used to create and/or validate this document.",
+ "format": "Document Reference",
+ "linked_refs": null,
+ "multiple": false,
+ "required": "optional",
+ "type": [
+ "Proposal Form Template",
+ "Proposal Comment Form Template",
+ "Brand Parameters Form Template",
+ "Campaign Parameters Form Template",
+ "Category Parameters Form Template",
+ "Contest Parameters Form Template",
+ "Rep Profile Form Template",
+ "Rep Nomination Form Template"
+ ],
+ "validation": "In addition to the validation performed for `Document Reference` type fields, \nThe document payload is not valid if it does not validate completely against the referenced template."
+ },
+ "type": {
+ "description": "The document TYPE.",
+ "format": "Document Type",
+ "required": "yes",
+ "validation": "**MUST** be a known document type."
+ },
+ "ver": {
+ "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`\n\n`ver` represents either:\n\n* when a document changes over time, such as\n\twith a new version of a particular document that supersedes an \n\tearlier one.\n* when a new document in a sequence of documents is produced.\n\t\nBecause the most common use `ver` is a new version of the same document\nthis is to be assumed unless the document specifies its representing\na sequence of documents.",
+ "format": "Document Ver",
+ "required": "yes",
+ "validation": "The document version must always be >= the document ID."
+ }
+ },
+ "order": [
+ "type",
+ "id",
+ "ver",
+ "ref",
+ "template",
+ "reply",
+ "section",
+ "collaborators",
+ "revocations",
+ "parameters",
+ "chain"
+ ]
+ }
}
diff --git a/specs/signed_docs/cose_headers.cue b/specs/signed_docs/cose_headers.cue
deleted file mode 100644
index 7c809138aa..0000000000
--- a/specs/signed_docs/cose_headers.cue
+++ /dev/null
@@ -1,222 +0,0 @@
-// Signed Document Definitions
-//
-// COSE Headers and Constraints
-package signed_docs
-
-import (
- "list"
- "github.com/input-output-hk/catalyst-libs/specs/generic:optional"
-)
-
-// Content Type name : Description
-_contentTypes: {
- [string]: {
- description: string // description of the content type
- coap_type?: int
- }
-}
-_contentTypes: {
- "application/json": {
- description: "JSON Document"
- coap_type: 50
- }
- "application/schema+json": {
- description: """
- JSON Schema Draft 7 Document; Note:
- * This is currently an unofficial media type.
- * Draft 7 is used because of its wide support by tooling.
- """
- }
- "application/cbor": {
- description: "RFC8949 Binary CBOR Encoded Document"
- coap_type: 60
- }
- "application/cddl": {
- description: """
- CDDL Document; Note:
- * This is an unofficial media type
- * RFC9165 Additional Control Operators for CDDL are supported.
- * Must not have Modules, schema must be self-contained.
- """
- }
-}
-
-contentTypes: _contentTypes
-
-// Content Encoding Type name : Description
-_encodingTypes: {
- [string]: {
- description: string // description of the content type
- }
-}
-_encodingTypes: {
- "br": {
- description: "BROTLI Compression"
- }
-}
-
-encodingTypes: _encodingTypes
-
-documentationLinks: {
- "application/json": "https://www.iana.org/assignments/media-types/application/json"
- "application/schema+json": "https://datatracker.ietf.org/doc/draft-bhutton-json-schema/"
- "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor"
- "br": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br"
- "JSON Schema": "https://json-schema.org/draft-07"
- "RFC7932": "https://www.rfc-editor.org/rfc/rfc7932" // Brotli
- "RFC8259": "https://www.rfc-editor.org/rfc/rfc8259.html" // JSON
- "RFC8610": "https://www.rfc-editor.org/rfc/rfc8610" // CDDL
- "RFC8949": "https://www.rfc-editor.org/rfc/rfc8949.html" // CBOR
- "RFC9052": "https://datatracker.ietf.org/doc/html/rfc9052" // COSE
- "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si" // COSE Multiple Signers
- "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1" // COSE Header Parameters
- "RFC9165": "https://www.rfc-editor.org/rfc/rfc9165" // CDDL Additional Controls
-}
-
-// Known aliases for links. Lets us automatically create [Named Link][Reference Link]
-linkAKA: {
- "BROTLI": "RFC7932"
- "JSON": "RFC8259"
- "CDDL": "RFC8610"
- "CBOR": "RFC8949"
- "COSE": "RFC9052"
- "COSE Sign": "RFC9052-CoseSign"
- "COSE Header Parameters": "RFC9052-HeaderParameters"
- "RFC9165 - CDDL Additional Controls": "RFC9165"
-}
-
-#allContentTypes: [
- for k, _ in _contentTypes {k},
-]
-
-_allCoapTypes: [
- for _, v in _contentTypes if v.coap_type != _|_ {v.coap_type},
-]
-
-_allCoapTypesStr: [
- for v in _allCoapTypes {"\(v)"},
-]
-
-_allCoapTypes: list.UniqueItems
-
-#contentTypesConstraint: or(#allContentTypes)
-
-// Supported Content Types (list of values)
-//#contentType: #allContentTypes | *"application/json"
-#contentType: #contentTypesConstraint | *#allContentTypes[0]
-
-// Supported content encodings (list of values)
-// All documents support content encoding, this defines the supported encoding types.
-// Documents may also not encode data, and will omit this field.
-#contentEncoding: ["br"]
-
-#contentEncodings: [...#contentEncoding]
-
-// Canonical List of COSE header names
-_coseHeaderNames: list.UniqueItems
-_coseHeaderNames: [
- "alg",
- "crit",
- "content type",
- "content-encoding", // Not strictly a true Cose Header, but we include it because of its relationship to `content type`
- "kid",
- "IV",
- "Partial IV",
- "counter signature",
-]
-
-_allCoseHeaderNames: or([
- for k in _coseHeaderNames {k},
-])
-
-coseHeaderFormats: #metadataFormats & {
- "Media Type": {
- description: "A Media Type string which identifies the payload."
- cddl: "media_type"
- }
- "HTTP Content Encoding": {
- description: "Encoding if any on the payload."
- cddl: "http_content_encoding"
- }
- "Catalyst ID": {
- description: "KID (Catalyst ID URI)"
- cddl: "catalyst_id_kid"
- }
-}
-
-// Types of a Metadata Fields
-#coseHeaderTypes: [
- for k, _ in coseHeaderFormats {k},
-]
-
-// Constraint of Types of Cose Header Fields
-#coseHeaderTypesConstraint: or(#coseHeaderTypes)
-
-#coseField: {
- coseLabel: int | string
- description: string
- required: optional.#field | *"yes"
- format: #coseHeaderTypesConstraint
- if format == "Media Type" {
- "value": #contentType | [...#contentType]
- }
-
- if format == "HTTP Content Encoding" {
- "value": #contentEncoding
- }
-}
-
-// Metadata Fields that are required for every signed document
-#coseHeaders: {
- [_allCoseHeaderNames]: #coseField
-}
-_coseHeaders: #coseHeaders & {
- // Documents content type
- "content type": #coseField & {
- coseLabel: 3
- format: "Media Type"
- description: "Media Type/s allowed in the Payload"
- }
- // Documents Used content encodings
- "content-encoding": #coseField & {
- coseLabel: "content-encoding"
- format: "HTTP Content Encoding"
- required: "optional"
- description: """
- Supported HTTP Encodings of the Payload.
- If no compression or encoding is used, then this field must not be present.
- """
- }
-}
-
-_coseSignatureHeaders: #coseHeaders & {
- // Key identifier
- "kid": #coseField & {
- coseLabel: 4
- format: "Catalyst ID"
- description: """
- Catalyst ID URI identifying the Public Key.
-
- The `kid` is a UTF-8 encoded Catalyst ID URI.
- Any `kid` URI which conforms to the Catalyst ID specification may be used.
- The Catalyst ID unambiguously defines both the signing keys and signing algorithm
- used to sign the protected portion of the document.
- """
- }
-}
-
-cose_headers: _coseHeaders
-cose_headers:
- "content type":
- value: #allContentTypes
-
-// Preferred display order of cose header fields.
-// if header not listed, display after the listed fields, in alphabetical order.
-cose_headers_order: list.UniqueItems
-cose_headers_order: [
- "content type",
- "content-encoding",
-]
-
-// Headers defined for signatures.
-cose_signature_headers: _coseSignatureHeaders
diff --git a/specs/signed_docs/docs/all.cue b/specs/signed_docs/docs/all.cue
deleted file mode 100644
index a0859b3102..0000000000
--- a/specs/signed_docs/docs/all.cue
+++ /dev/null
@@ -1,109 +0,0 @@
-// Master list of all document types.
-package signed_docs
-
-import (
- "list"
-)
-
-// Named Type UUIDs for easier definitions/references
-_allDocTypes: {
- "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f"
- "Proposal": "7808d2ba-d511-40af-84e8-c0d1625fdfdc"
- "Comment": "b679ded3-0e7c-41ba-89f8-da62a17898ea"
- "Action": "5e60e623-ad02-4a1b-a1ac-406db978ee48"
- "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65"
- "ModerationAction": "a5d232b8-5e03-4117-9afd-be32b878fcdd"
- "Brand": "ebcabeeb-5bc5-4f95-91e8-cab8ca724172"
- "Campaign": "5ef32d5d-f240-462c-a7a4-ba4af221fa23"
- "Category": "818938c3-3139-4daa-afe6-974c78488e95"
- "Decision": "788ff4c6-d65a-451f-bb33-575fe056b411"
-}
-
-// Source of truth for ALL Document Types and their matching UUID's.
-// Format is : :
-_allDocs: {
- "Proposal Meta Template": [
- _allDocTypes["Template"], // Template
- _allDocTypes["Template"], // For Templates
- _allDocTypes["Proposal"], // On Proposals
- ]
- "Proposal Template": [
- _allDocTypes["Template"], // Template
- _allDocTypes["Proposal"], // For Proposals
- ]
- "Proposal": [
- _allDocTypes["Proposal"],
- ]
- "Proposal Comment Meta Template": [
- _allDocTypes["Template"], // Template
- _allDocTypes["Template"], // For Templates
- _allDocTypes["Comment"], // On Comment
- _allDocTypes["Proposal"], // On Proposals
- ]
- "Proposal Comment Template": [
- _allDocTypes["Template"], // Template
- _allDocTypes["Comment"], // For Comments
- _allDocTypes["Proposal"], // On Proposals
- ]
- "Proposal Comment": [
- _allDocTypes["Comment"], // Comment
- _allDocTypes["Proposal"], // For Proposals
- ]
- "Proposal Submission Action":
- [
- _allDocTypes["Action"], // Action
- _allDocTypes["Proposal"], // For Proposal
- _allDocTypes["SubmissionAction"], // On Submission
- ]
- "Proposal Moderation Action":
- [
- _allDocTypes["Action"], // Action
- _allDocTypes["Proposal"], // For Proposal
- _allDocTypes["ModerationAction"], // On Moderation
- ]
- "Comment Moderation Action": [
- _allDocTypes["Action"], // Action
- _allDocTypes["Comment"], // For Comment
- _allDocTypes["ModerationAction"], // On Moderation
- ]
- "Brand Parameters": [
- _allDocTypes["Brand"],
- ]
- "Campaign Parameters": [
- _allDocTypes["Campaign"],
- ]
- "Category Parameters": [
- _allDocTypes["Category"],
- ]
- "Decision Parameters": [
- _allDocTypes["Decision"],
- ]
-
-}
-
-// Document Cluster Definition
-#DocumentCluster: {
- docs: [..._allDocNames]
-}
-
-#DocClusters: {
- [string]: #DocumentCluster
-}
-
-doc_clusters: #DocClusters & {
- // System parameters define the system, excludes Decisions.
- "System Parameters": {
- docs: [
- "Brand Parameters",
- "Campaign Parameters",
- "Category Parameters",
- ]
- }
-}
-
-// A Doc can only be in 1 cluster.
-#allDocClusterDocs: list.UniqueItems
-#allDocClusterDocs: [...string] & [
- for cluster in doc_clusters
- for doc in cluster.docs {doc},
-]
diff --git a/specs/signed_docs/docs/brand_parameters.cue b/specs/signed_docs/docs/brand_parameters.cue
deleted file mode 100644
index 75deb70f29..0000000000
--- a/specs/signed_docs/docs/brand_parameters.cue
+++ /dev/null
@@ -1,21 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Brand Parameters": {
-
- description: """
- Parameters which define this brand within the system.
- """
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/campaign_parameters.cue b/specs/signed_docs/docs/campaign_parameters.cue
deleted file mode 100644
index 9cafb80ba5..0000000000
--- a/specs/signed_docs/docs/campaign_parameters.cue
+++ /dev/null
@@ -1,34 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Campaign Parameters": {
- description: """
- Parameters which define a Campaign within a Brand in the system.
- """
-
- metadata: {
- parameters: {
- required: "yes"
- type: "Brand Parameters"
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/category_parameters.cue b/specs/signed_docs/docs/category_parameters.cue
deleted file mode 100644
index 7d8904f7db..0000000000
--- a/specs/signed_docs/docs/category_parameters.cue
+++ /dev/null
@@ -1,35 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Category Parameters": {
-
- description: """
- Parameters which define a Category withing a Campaign under a Brand in the system.
- """
-
- metadata: {
- parameters: {
- required: "yes"
- type: "Campaign Parameters"
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/decision_parameters.cue b/specs/signed_docs/docs/decision_parameters.cue
deleted file mode 100644
index 133d908d5e..0000000000
--- a/specs/signed_docs/docs/decision_parameters.cue
+++ /dev/null
@@ -1,34 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Decision Parameters": {
- description: """
- Parameters which define an individual voting event.
- """
-
- metadata: {
- parameters: {
- required: "yes"
- type: doc_clusters."System Parameters".docs
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/proposal_comment_meta_template.cue b/specs/signed_docs/docs/proposal_comment_meta_template.cue
deleted file mode 100644
index f335f592c8..0000000000
--- a/specs/signed_docs/docs/proposal_comment_meta_template.cue
+++ /dev/null
@@ -1,70 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Proposal Comment Meta Template": {
- description: """
- ## Proposal Comment Meta Template Document
-
- A Proposal Comment Meta Template is used to enforce functional requirements
- are met in any Proposal Comment Template.
-
- The payload of a proposal comment template is controlled by its meta template.
- """
-
- headers: {
- "content type": {
- value: "application/schema+json"
- }
- }
-
- metadata: {
- parameters: {
- required: "yes"
- type: doc_clusters."System Parameters".docs
- }
- }
-
- payload: {
- description: """
- JSON Schema document which ensures the minimum required functional requirements
- of the Proposal Comment Template are met.
-
- This ensures that payloads can be reliably interpreted by business logic processes,
- while allowing for flexibility to capture extended information.
- """
-
- schema: "https://json-schema.org/draft-07/schema"
- }
-
- "signers": {
- roles: {
- // No User Role may publish this document.
- user: []
-
- // Root Admin and brand Admin may publish this document.
- admin: [
- "Root Admin",
- "Brand Admin",
- ]
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/proposal_comment_template.cue b/specs/signed_docs/docs/proposal_comment_template.cue
deleted file mode 100644
index b64d401d56..0000000000
--- a/specs/signed_docs/docs/proposal_comment_template.cue
+++ /dev/null
@@ -1,72 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Proposal Comment Template": {
- description: """
- ## Proposal Comment Template Document
-
- A Proposal Comment Template defines the allowed payload contents of a
- linked proposal comment.
-
- Proposal comments themselves are intentionally general, however they may be
- linked to a brand/campaign or category via the template used by the proposal.
-
- The payload of a proposal comment is controlled by its template.
- """
-
- headers: {
- "content type": {
- value: "application/schema+json"
- }
- }
-
- metadata: {
- template: {
- required: "optional"
- type: "Proposal Comment Meta Template"
- }
-
- parameters: {
- required: "yes"
- type: doc_clusters."System Parameters".docs
- }
- }
-
- payload: {
- description: """
- JSON Schema document which defines the content of the Proposal Comments.
- """
- }
-
- signers: {
- roles: {
- // No User Role may publish this document.
- user: []
-
- // Brand Admin and Lower may publish this document.
- admin: [
- "Brand Admin",
- "Campaign Admin",
- ]
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]}
-}
diff --git a/specs/signed_docs/docs/proposal_meta_template.cue b/specs/signed_docs/docs/proposal_meta_template.cue
deleted file mode 100644
index 6fd78e3814..0000000000
--- a/specs/signed_docs/docs/proposal_meta_template.cue
+++ /dev/null
@@ -1,71 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Proposal Meta Template": {
- description: """
- ## Proposal Meta Template Document
-
- A Proposal Meta Template is used to enforce functional requirements
- are met in any Proposal Template.
-
- The payload of a proposal template is controlled by its meta template.
- """
-
- headers: {
- "content type": {
- value: "application/schema+json"
- }
- }
-
- metadata: {
- parameters: {
- required: "yes"
- type: doc_clusters."System Parameters".docs
- }
- }
-
- payload: {
- description: """
- JSON Schema document which ensures the minimum required functional requirements
- of the Proposal Template are met.
-
- This ensures that payloads can be reliably interpreted by business logic processes,
- while allowing for flexibility to capture extended information.
- """
-
- schema: "https://json-schema.org/draft-07/schema"
- }
-
- "signers": {
- roles: {
- // No User Role may publish this document.
- user: []
-
- // Root Admin and brand Admin may publish this document.
- admin: [
- "Root Admin",
- "Brand Admin",
- ]
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]
- }
-}
diff --git a/specs/signed_docs/docs/proposal_template.cue b/specs/signed_docs/docs/proposal_template.cue
deleted file mode 100644
index 845059d022..0000000000
--- a/specs/signed_docs/docs/proposal_template.cue
+++ /dev/null
@@ -1,76 +0,0 @@
-package signed_docs
-
-// Proposal Document Definition
-
-docs: #DocumentDefinitions & {
- "Proposal Template": {
- description: """
- ## Proposal Template Document
-
- A Proposal Template defines the allowed payload contents of a
- linked proposal.
-
- Proposals themselves are intentionally general, however they may be
- linked to a brand/campaign or category via the template used by the proposal.
-
- The payload of a proposal is controlled by its template.
- """
-
- headers: {
- "content type": {
- value: "application/schema+json"
- }
- }
-
- metadata: {
- template: {
- required: "optional"
- type: "Proposal Meta Template"
- }
-
- parameters: {
- required: "yes"
- type: doc_clusters."System Parameters".docs
- linked_refs: [
- "template",
- ]
- }
- }
-
- payload: {
- description: """
- JSON Schema document which defines the valid contents of a proposal document.
- """
- }
-
- signers: {
- roles: {
- // No User Role may publish this document.
- user: []
-
- // Brand Admin and Lower may publish this document.
- admin: [
- "Brand Admin",
- "Campaign Admin",
- ]
- }
- }
-
- versions: [
- {
- version: "0.01"
- modified: "2025-04-04"
- changes: """
- * First Published Version
- """
- },
- {
- version: "0.03"
- modified: "2025-05-05"
- changes: """
- * Use generalized parameters.
- """
- },
- ]
- }
-}
diff --git a/specs/signed_docs/documentation_links.cue b/specs/signed_docs/documentation_links.cue
deleted file mode 100644
index 4083dd2d34..0000000000
--- a/specs/signed_docs/documentation_links.cue
+++ /dev/null
@@ -1,55 +0,0 @@
-// Links to external documentation
-
-package signed_docs
-
-import (
- "list"
-)
-
-// A named Link to an external document, this would be encoded into markdown as:
-// [name]: url
-#metadataStruct: {
- [_allMetadataNames]: #metadataField
-}
-
-#namedLink: {
- [string]: string
-}
-
-// Constrains the URLs being linked to be unique
-#uniqueLinkValues: list.UniqueItems
-#uniqueLinkValues: [...string] & [
- for _, v in documentationLinks {v},
-]
-
-documentationLinks: #namedLink
-documentationLinks: {
- "RFC3629": "https://datatracker.ietf.org/doc/html/rfc3629" // UTF-8
- "RFC3986": "https://datatracker.ietf.org/doc/html/rfc3986" // URI
- "RFC9562": "https://www.rfc-editor.org/rfc/rfc9562.html" // UUID
- "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4" // UUID V4
- "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7" // UUID V7
- "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode" // CC BY 4.0
- "IPFS-CID": "https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid" // IPFS Content Identifier
- "CBOR-TAG-42": "https://github.com/ipld/cid-cbor/"
- "CBOR-TAG-37": "https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md" // IPLD content identifiers (CIDs) in CBOR
-}
-
-#allLinkNames: or([
- for k, _ in documentationLinks {k},
-])
-
-linkAKA: {
- [string]: #allLinkNames
-}
-
-// Known aliases for links. Lets us automatically create [Named Link][Reference Link]
-linkAKA: {
- "UUIDv7": "RFC9562-V7"
- "UUIDv4": "RFC9562-V4"
- "UUID": "RFC9562"
- "URI": "RFC3986"
- "UTF-8": "RFC3629"
- "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42"
- "IPFS CID": "IPFS-CID"
-}
diff --git a/specs/signed_docs/payload.cue b/specs/signed_docs/payload.cue
deleted file mode 100644
index f2dcbec41c..0000000000
--- a/specs/signed_docs/payload.cue
+++ /dev/null
@@ -1,10 +0,0 @@
-package signed_docs
-
-// Payload definition
-_payload: {
- // Description of the payload
- description: string
- // Optional fixed schema for the payload.
- // A URI or inline JSON Schema that the payload must validate against.
- schema?: _
-}
| | |