From f47890bfca127f988249d6f3e0b4eb0929b14993 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Thu, 15 May 2025 17:46:32 +0700 Subject: [PATCH 1/6] fix(docs): correct python type annotations in documentation generator (#325) * feat(docs): Consolidate all parameters types into a single parameters reference. * fix(docs): Fix linked references * feat(docs): Start of adding capability to cluster like documents to simplify relationship diagrams. * fix(docs): wip fix of clustered documents * feat(docs): Add document clusters to help with autogenerated diagrams. * fix(docs): fix spelling * fix(Python): fix type * fix(docs): Inter doc links in diagrams * fix(docs): Neils Eyesight Soother * fix(docs): Rename Election Parameters to Decision parameters * fix(docs): python types * fix(docs): add missing doc generator type definitions * fix(general): Updater recommended vscode settings --- .vscode/settings.recommended.json | 12 +++- .../08_concepts/signed_doc/diagrams/all.dot | 2 +- specs/gen_docs/gen/doc_generator.py | 6 +- .../gen_docs/gen/doc_relationship_diagrams.py | 4 +- specs/gen_docs/gen/graphviz_doc_diagram.py | 39 ++++++++----- specs/gen_docs/spec/document.py | 23 ++++++-- specs/gen_docs/spec/signed_doc.py | 57 +++++++++++-------- 7 files changed, 91 insertions(+), 52 deletions(-) diff --git a/.vscode/settings.recommended.json b/.vscode/settings.recommended.json index c152c545fd..c63dff43ce 100644 --- a/.vscode/settings.recommended.json +++ b/.vscode/settings.recommended.json @@ -1,5 +1,5 @@ { - // Recommended `settings.json` configuration + "$comment": "Recommended `settings.json` configuration", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.organizeImports": true, @@ -37,12 +37,20 @@ "rust", "rust/c509-certificate", "rust/cardano-chain-follower", + "rust/catalyst-types", "rust/catalyst-voting", + "rust/immutable-ledger", + "rust/vote-tx-v1", + "rust/vote-tx-v2", + "rust/signed-doc", "rust/cbork", "rust/hermes-ipfs", + "rust/rbac-registration", + "rust/cardano-blockchain-types", "dart", "docs", - "general" + "general", + "deps" ], "conventionalCommits.gitmoji": false, "markdown.extension.toc.unorderedList.marker": "*", diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot index d22921c2f9..af9f30cf9e 100644 --- a/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot @@ -1,4 +1,4 @@ -digraph "None" { +digraph "All" { rankdir="LR" graph [fontname="helvetica", fontsize="32", fontcolor="#29235c", bgcolor="white"]; node [penwidth="0", margin="0", fontname="helvetica", fontsize="32", fontcolor="#29235c"]; diff --git a/specs/gen_docs/gen/doc_generator.py b/specs/gen_docs/gen/doc_generator.py index f392378355..aebfc401ba 100644 --- a/specs/gen_docs/gen/doc_generator.py +++ b/specs/gen_docs/gen/doc_generator.py @@ -170,7 +170,7 @@ def add_reference_links(self) -> None: actual_link_names = self._spec.link_names() - actual_links_used = {} + actual_links_used: dict[str, str] = {} for link_name in actual_link_names: esc_link_name = re.escape(link_name) link_name_regex = f"(^|\\s)({esc_link_name})(\\.|\\s|$)" @@ -190,7 +190,7 @@ def add_reference_links(self) -> None: 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: @@ -343,7 +343,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/gen_docs/gen/doc_relationship_diagrams.py index b7a0d68b2b..7f3c74fc3e 100644 --- a/specs/gen_docs/gen/doc_relationship_diagrams.py +++ b/specs/gen_docs/gen/doc_relationship_diagrams.py @@ -51,7 +51,7 @@ def generate(self) -> bool: # noqa: C901 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] = [] @@ -66,7 +66,7 @@ def generate(self) -> bool: # noqa: C901 doc_data = self._spec.get_document(doc) # Add content type explicitely to table. - doc_table.add_row(TableRow(name="content type", value=doc_data.headers["content type"].value)) + 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): diff --git a/specs/gen_docs/gen/graphviz_doc_diagram.py b/specs/gen_docs/gen/graphviz_doc_diagram.py index 3c2ec65b70..2c1d78ce06 100644 --- a/specs/gen_docs/gen/graphviz_doc_diagram.py +++ b/specs/gen_docs/gen/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/spec/document.py b/specs/gen_docs/spec/document.py index 1f9e8a9d39..c9c5414347 100644 --- a/specs/gen_docs/spec/document.py +++ b/specs/gen_docs/spec/document.py @@ -20,6 +20,11 @@ class DocumentBusinessLogic(BaseModel): model_config = ConfigDict(extra="forbid") +def empty_string_list() -> list[str]: + """Get an empty string list.""" + return [] + + class Document(BaseModel): """Document Data Definition.""" @@ -38,8 +43,8 @@ class Document(BaseModel): 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) + _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 @@ -74,11 +79,21 @@ def all_references(self) -> list[str]: return self._all_refs @property - def name(self) -> list[str]: + def name(self) -> str: """Get name of this document.""" - return self._name + 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.""" + content_type = self.headers.get("content type") + if content_type is not None: + content_type = content_type.value + if content_type is None: + content_type = "Undefined" + return content_type diff --git a/specs/gen_docs/spec/signed_doc.py b/specs/gen_docs/spec/signed_doc.py index e9f832b361..ad1ae1d771 100644 --- a/specs/gen_docs/spec/signed_doc.py +++ b/specs/gen_docs/spec/signed_doc.py @@ -32,17 +32,17 @@ class HeaderType(Enum): HEADERS: dict[str, dict[str, str]] = { - HeaderType.DOCUMENT: { + HeaderType.DOCUMENT.name: { "headers": "cose_headers", "order": "cose_headers_order", "format": "coseHeaderFormats", }, - HeaderType.SIGNATURE: { + HeaderType.SIGNATURE.name: { "headers": "cose_signature_headers", "order": "cose_signature_headers_order", "format": "coseHeaderFormats", }, - HeaderType.METADATA: { + HeaderType.METADATA.name: { "headers": "metadata", "order": "metadata_order", "format": "metadataFormats", @@ -80,7 +80,7 @@ class SignedDoc(BaseModel): 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) + data: dict[str, typing.Any] = json.load(f) doc = cls(**data) doc._data = data doc._file = spec_file @@ -121,19 +121,19 @@ def doc_in_cluster_name(self, doc_name: str) -> str | None: return cluster.name return None - def data(self) -> dict: + def data(self) -> dict[str, typing.Any]: """Return the raw spec data.""" return self._data def document_names(self) -> list[str]: """Get all documents.""" - return self.docs.keys() + return list(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() + metadata_formats: dict[str, typing.Any] = self._data[formats] + return list(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.""" @@ -151,9 +151,9 @@ def link_names(self) -> list[str]: def link_for_link_name(self, link_name: str) -> str: """Get a link for a link name.""" - return self.documentation_links[link_name] + return f"{self.documentation_links[link_name]}" - def header(self, header: str, header_type: HeaderType = HeaderType.DOCUMENT) -> dict: + def header(self, header: str, header_type: HeaderType = HeaderType.DOCUMENT) -> dict[str, typing.Any]: """Get Cose header definition.""" headers, _, _ = self.headers_and_order(header_type) return headers[header] @@ -166,14 +166,14 @@ 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]: + def headers_and_order(self, header_type: HeaderType) -> tuple[dict[str, typing.Any], 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_key = HEADERS[header_type.name]["headers"] + header_order_key = HEADERS[header_type.name]["order"] + formats = HEADERS[header_type.name]["format"] - headers: dict = self._data[headers] - header_order: list[str] = self._data.get(header_order, []) + headers: dict[str, typing.Any] = self._data[headers_key] + header_order: list[str] = self._data.get(header_order_key, []) # Make sure unordered headers get included in the documentation. for header in headers: @@ -187,7 +187,7 @@ def all_headers(self, header_type: HeaderType = HeaderType.DOCUMENT) -> list[str _, header_order, _ = self.headers_and_order(header_type) return header_order - def cddl_type_for_metadata(self, name: str | None, header_type: str) -> str: + def cddl_type_for_metadata(self, name: str, header_type: HeaderType) -> str: """Get the CDDL type for a given Metadata field.""" headers, _, formats = self.headers_and_order(header_type) @@ -198,19 +198,23 @@ def cddl_type_for_metadata(self, name: str | None, header_type: str) -> str: cddl_def = self._data[formats].get(cddl_def) if cddl_def is not None: cddl_def = cddl_def.get("cddl") + if cddl_def is None: + cddl_def = "Unknown" return cddl_def - def cddl_def(self, name: str) -> dict | None: # noqa: C901 + def cddl_def(self, name: str) -> dict[str, typing.Any] | None: # noqa: C901 """Get a cddl definition by name.""" - def synthetic_headers(defs: dict, header_type: HeaderType = HeaderType.METADATA) -> dict: + def synthetic_headers( # noqa: C901 + defs: dict[str, typing.Any], header_type: HeaderType = HeaderType.METADATA + ) -> dict[str, str]: """Generate a synthetic cddl def for this type. Needs to be generated from Metadata definitions. """ cddl_def = "" defs["requires"] = [] - exclusives = [] + exclusives: list[str] = [] headers, header_names, _ = self.headers_and_order(header_type) @@ -222,19 +226,22 @@ def synthetic_headers(defs: dict, header_type: HeaderType = HeaderType.METADATA) if exclusive is not None: exclusive.append(header) exclusive.sort() - if exclusive not in exclusives: - exclusives.append(exclusive) + for excl in exclusive: + if excl not in exclusives: + exclusives.append(excl) else: + requires: list[str] = defs["requires"] 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) + if cddl_type not in requires: + requires.append(cddl_type) + defs["requires"] = requires for exclusive_set in exclusives: # Exclusive sets are never required - exclusive_fields = [] + exclusive_fields: list[str] = [] for entry in exclusive_set: cddl_type = self.cddl_type_for_metadata(entry, header_type) field_name = headers[entry].get("coseLabel", entry) From 3ffc8e56273f132d9a4f80407cc9d53f5efdb9a6 Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Fri, 16 May 2025 16:15:57 +0700 Subject: [PATCH 2/6] docs(docs): Better define the document encoding restrictions. (#326) --- .../signed_doc/docs/brand_parameters.md | 2 +- .../signed_doc/docs/campaign_parameters.md | 2 +- .../signed_doc/docs/category_parameters.md | 2 +- .../docs/comment_moderation_action.md | 2 +- .../signed_doc/docs/decision_parameters.md | 2 +- .../08_concepts/signed_doc/docs/proposal.md | 2 +- .../signed_doc/docs/proposal_comment.md | 2 +- .../docs/proposal_comment_meta_template.md | 2 +- .../docs/proposal_comment_template.md | 2 +- .../signed_doc/docs/proposal_meta_template.md | 2 +- .../docs/proposal_moderation_action.md | 2 +- .../docs/proposal_submission_action.md | 2 +- .../signed_doc/docs/proposal_template.md | 2 +- .../08_concepts/signed_doc/metadata.md | 2 +- .../08_concepts/signed_doc/spec.md | 45 ++++++++++++++++++- .../08_concepts/signed_doc/types.md | 2 +- specs/gen_docs/gen/spec_md.py | 36 ++++++++++++++- specs/signed_doc.json | 7 +++ specs/signed_docs/authors_copyright.cue | 11 +++++ specs/signed_docs/documentation_links.cue | 20 +++++---- 20 files changed, 123 insertions(+), 26 deletions(-) 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..8f2571f9e8 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 @@ -112,7 +112,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/campaign_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md index 40b40909c1..8836c1999a 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 @@ -130,7 +130,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/category_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md index 07f5156139..7f123e98fc 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 @@ -130,7 +130,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/comment_moderation_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/comment_moderation_action.md index 5b9907ca1f..e8bd4caf85 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 @@ -153,7 +153,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/decision_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md index 95e049ecf2..dc128901ba 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/decision_parameters.md @@ -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 | 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..70bffb1365 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md @@ -226,7 +226,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..984dd48cf3 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 @@ -261,7 +261,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_comment_meta_template.md index 305e9d497f..73280ae4f7 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_comment_meta_template.md @@ -141,7 +141,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_template.md index 91c7b241f9..ff64f26852 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_template.md @@ -154,7 +154,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_meta_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md index 9ff14e8810..dd91bf8185 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md @@ -141,7 +141,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_moderation_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md index b8236d4597..8792ac4368 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 @@ -153,7 +153,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_submission_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md index 68d7f89c2e..c6647234c2 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 @@ -260,7 +260,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_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md index b01b6eb41c..53ac87aff1 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md @@ -158,7 +158,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/metadata.md b/docs/src/architecture/08_concepts/signed_doc/metadata.md index 7b6fdc2e13..8daa80ac97 100644 --- a/docs/src/architecture/08_concepts/signed_doc/metadata.md +++ b/docs/src/architecture/08_concepts/signed_doc/metadata.md @@ -348,7 +348,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/spec.md b/docs/src/architecture/08_concepts/signed_doc/spec.md index f2cc3a81bb..222eff96a0 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 @@ -120,7 +154,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,6 +172,15 @@ used to sign the protected portion of the document. * Use generalized parameters. +#### 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 [application/schema+json]: https://datatracker.ietf.org/doc/draft-bhutton-json-schema/ [RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 [application/cbor]: https://www.iana.org/assignments/media-types/application/cbor diff --git a/docs/src/architecture/08_concepts/signed_doc/types.md b/docs/src/architecture/08_concepts/signed_doc/types.md index c9b878b78e..35c823f1a5 100644 --- a/docs/src/architecture/08_concepts/signed_doc/types.md +++ b/docs/src/architecture/08_concepts/signed_doc/types.md @@ -55,7 +55,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/specs/gen_docs/gen/spec_md.py b/specs/gen_docs/gen/spec_md.py index bd8638c8db..f70b4345ac 100644 --- a/specs/gen_docs/gen/spec_md.py +++ b/specs/gen_docs/gen/spec_md.py @@ -23,7 +23,7 @@ def header_parameter_doc(self, header: str, header_type: HeaderType) -> str: if not isinstance(label, str): custom_header = "" header_format = options["format"] - header_value = options.get("value", None) + header_value: str | list[str] | None = options.get("value", None) header_format_display = f"{header_format}" if isinstance(header_value, list) and len(header_value) > 0: header_format_display += "\n * Supported Values:" @@ -93,6 +93,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)} diff --git a/specs/signed_doc.json b/specs/signed_doc.json index 9706ba0d6b..0f99c89676 100644 --- a/specs/signed_doc.json +++ b/specs/signed_doc.json @@ -253,6 +253,11 @@ "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" } ] }, @@ -2066,6 +2071,7 @@ } }, "documentationLinks": { + "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", @@ -2097,6 +2103,7 @@ "linkAKA": { "BROTLI": "RFC7932", "CBOR": "RFC8949", + "CBOR Deterministic Encoding": "CBOR-LFD-ENCODING", "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42", "CDDL": "RFC8610", "COSE": "RFC9052", diff --git a/specs/signed_docs/authors_copyright.cue b/specs/signed_docs/authors_copyright.cue index c354a5b10e..2d9a8314d8 100644 --- a/specs/signed_docs/authors_copyright.cue +++ b/specs/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/documentation_links.cue b/specs/signed_docs/documentation_links.cue index 4083dd2d34..ff9f1bc98d 100644 --- a/specs/signed_docs/documentation_links.cue +++ b/specs/signed_docs/documentation_links.cue @@ -24,15 +24,16 @@ import ( 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 + "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 } #allLinkNames: or([ @@ -52,4 +53,5 @@ linkAKA: { "UTF-8": "RFC3629" "CBOR Encoded IPLD Content Identifier": "CBOR-TAG-42" "IPFS CID": "IPFS-CID" + "CBOR Deterministic Encoding": "CBOR-LFD-ENCODING" } From e4d08195f48554270a92241d9e12a12a0b4fdbef Mon Sep 17 00:00:00 2001 From: Steven Johnson Date: Wed, 21 May 2025 11:18:43 +0700 Subject: [PATCH 3/6] feat(docs): Add examples for predefined document schemas (#342) --- .../docs/proposal_submission_action.md | 133 +++++--- specs/gen_docs/gen/docs_page_md.py | 22 +- specs/gen_docs/pyproject.toml | 1 + specs/gen_docs/spec/payload.py | 108 +++++++ specs/gen_docs/uv.lock | 298 +++++++++++++++--- specs/signed_doc.json | 23 ++ ...posal_submission_action.draft.example.json | 3 + ...posal_submission_action.final.example.json | 3 + ...oposal_submission_action.hide.example.json | 3 + .../docs/proposal_submission_action.cue | 27 ++ specs/signed_docs/payload.cue | 17 + 11 files changed, 539 insertions(+), 99 deletions(-) create mode 100644 specs/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json create mode 100644 specs/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json create mode 100644 specs/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json 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 c6647234c2..e15b76b4be 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 @@ -199,49 +199,106 @@ States: `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 diff --git a/specs/gen_docs/gen/docs_page_md.py b/specs/gen_docs/gen/docs_page_md.py index 970f2d4836..b07c17f440 100644 --- a/specs/gen_docs/gen/docs_page_md.py +++ b/specs/gen_docs/gen/docs_page_md.py @@ -1,11 +1,8 @@ """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 @@ -62,24 +59,7 @@ 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.""" diff --git a/specs/gen_docs/pyproject.toml b/specs/gen_docs/pyproject.toml index 6626530ffb..5ac71cbe38 100644 --- a/specs/gen_docs/pyproject.toml +++ b/specs/gen_docs/pyproject.toml @@ -5,6 +5,7 @@ description = "Generate Signed Document documentation files." readme = "README.md" requires-python = ">=3.13" dependencies = [ + "jsonschema[format]>=4.23.0", "pydantic>=2.11.4", "pydot>=3.0.4", "rich>=14.0.0", diff --git a/specs/gen_docs/spec/payload.py b/specs/gen_docs/spec/payload.py index 732682508c..3caa4efdc0 100644 --- a/specs/gen_docs/spec/payload.py +++ b/specs/gen_docs/spec/payload.py @@ -1,14 +1,122 @@ """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 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 + 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. + jsonschema.Draft7Validator.check_schema(schema) + validator = jsonschema.Draft7Validator(schema, format_checker=jsonschema.draft7_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" + + 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/gen_docs/uv.lock b/specs/gen_docs/uv.lock index 5a05c6644e..06aaec055a 100644 --- a/specs/gen_docs/uv.lock +++ b/specs/gen_docs/uv.lock @@ -6,9 +6,40 @@ requires-python = ">=3.13" 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" } +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" }, + { 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]] @@ -16,6 +47,7 @@ name = "gen-docs" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "jsonschema", extra = ["format"] }, { name = "pydantic" }, { name = "pydot" }, { name = "rich" }, @@ -24,12 +56,82 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "jsonschema", extras = ["format"], specifier = ">=4.23.0" }, { 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 = "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.23.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/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778, upload-time = "2024-07-08T18:40:05.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462, upload-time = "2024-07-08T18:40:00.165Z" }, +] + +[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" @@ -37,18 +139,18 @@ 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" } +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" }, + { 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" } +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" }, + { 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]] @@ -61,9 +163,9 @@ dependencies = [ { 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" } +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" }, + { 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]] @@ -73,25 +175,25 @@ 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" } +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" }, + { 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]] @@ -101,27 +203,73 @@ 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" } +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" }, + { 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" } +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" }, + { 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" } +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" }, + { 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]] @@ -132,9 +280,9 @@ 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" } +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" }, + { 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]] @@ -144,18 +292,70 @@ 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" } +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" }, + { 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 = "rpds-py" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/d2/7bed8453e53f6c9dea7ff4c19ee980fd87be607b2caf023d62c6579e6c30/rpds_py-0.25.0.tar.gz", hash = "sha256:4d97661bf5848dd9e5eb7ded480deccf9d32ce2cd500b88a26acbf7bd2864985", size = 26822, upload-time = "2025-05-15T13:42:03.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/d9/6534d5a9d00038261894551ee8043267f17c019e6c0df3c7d822fb5914f1/rpds_py-0.25.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4e5fe366fa53bd6777cf5440245366705338587b2cf8d61348ddaad744eb591a", size = 364375, upload-time = "2025-05-15T13:39:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/af/9d/f90c079635017cc50350cbbbf2c4fea7b2a75a24bea92211da1b0c52d55f/rpds_py-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54f925ff8d4443b7cae23a5215954abbf4736a3404188bde53c4d744ac001d89", size = 350284, upload-time = "2025-05-15T13:39:27.336Z" }, + { url = "https://files.pythonhosted.org/packages/f9/04/b54c5b3abdccf03ca3ec3317bd68caaa7907a61fea063096ee08d128b6ed/rpds_py-0.25.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58258a66255b2500ddaa4f33191ada5ec983a429c09eb151daf81efbb9aa115", size = 392107, upload-time = "2025-05-15T13:39:30.99Z" }, + { url = "https://files.pythonhosted.org/packages/aa/99/001bc3ab81c1798ee4c7bba7950134258d899e566d6839b6696b47248f71/rpds_py-0.25.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f3a57f08c558d0983a708bfe6d1265f47b5debff9b366b2f2091690fada055c", size = 398612, upload-time = "2025-05-15T13:39:32.505Z" }, + { url = "https://files.pythonhosted.org/packages/00/e1/e22893e1043938811a50c857a5780e0a4e2da02dd10ac041ecca1044906a/rpds_py-0.25.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7d60d42f1b9571341ad2322e748f7a60f9847546cd801a3a0eb72a1b54c6519", size = 452190, upload-time = "2025-05-15T13:39:34.024Z" }, + { url = "https://files.pythonhosted.org/packages/fb/6c/7071e6d27e784ac33ab4ca048eb550b5fc4f381b29e9ba33254bc6e7eaf6/rpds_py-0.25.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a54b94b0e4de95aa92618906fb631779d9fde29b4bf659f482c354a3a79fd025", size = 440634, upload-time = "2025-05-15T13:39:36.048Z" }, + { url = "https://files.pythonhosted.org/packages/57/17/7343ea3ec906ee8c2b64a956d702de5067e0058b5d2869fbfb4b11625112/rpds_py-0.25.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af1c2241919304cc2f90e7dcb3eb1c1df6fb4172dd338e629dd6410e48b3d1a0", size = 391000, upload-time = "2025-05-15T13:39:37.802Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ad/9b3c3e950108073448834f0548077e598588efa413ba8dcc91e7ad6ff59d/rpds_py-0.25.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7d34547810bfd61acf8a441e8a3651e7a919e8e8aed29850be14a1b05cfc6f41", size = 424621, upload-time = "2025-05-15T13:39:39.409Z" }, + { url = "https://files.pythonhosted.org/packages/57/06/bd99ca30a6e539c18c6175501c1dd7f9ef0640f7b1dc0b14b094785b509a/rpds_py-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:66568caacf18542f0cf213db7adf3de2da6ad58c7bf2c4fafec0d81ae557443b", size = 569529, upload-time = "2025-05-15T13:39:41.011Z" }, + { url = "https://files.pythonhosted.org/packages/c5/79/93381a25668466502adc082d3ce2a9ff35f8116e5e2711cedda0bfcfd699/rpds_py-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e49e4c3e899c32884d7828c91d6c3aff08d2f18857f50f86cc91187c31a4ca58", size = 594638, upload-time = "2025-05-15T13:39:43.15Z" }, + { url = "https://files.pythonhosted.org/packages/91/ee/371ecc045d65af518e2210ad018892b1f7a7a21cd64661156b4d29dfd839/rpds_py-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:20af08b0b2d5b196a2bcb70becf0b97ec5af579cee0ae6750b08a2eea3b6c77d", size = 561413, upload-time = "2025-05-15T13:39:45.3Z" }, + { url = "https://files.pythonhosted.org/packages/34/c4/85e9853312b7e5de3c98f100280fbfd903e63936f49f6f11e4cd4eb53299/rpds_py-0.25.0-cp313-cp313-win32.whl", hash = "sha256:d3dc8d6ce8f001c80919bdb49d8b0b815185933a0b8e9cdeaea42b0b6f27eeb0", size = 222326, upload-time = "2025-05-15T13:39:46.777Z" }, + { url = "https://files.pythonhosted.org/packages/65/c6/ac744cc5752b6f291b2cf13e19cd7ea3cafe68922239a3b95f05f39287b7/rpds_py-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:113d134dc5a8d2503630ca2707b58a1bf5b1b3c69b35c7dab8690ee650c111b8", size = 234772, upload-time = "2025-05-15T13:39:48.804Z" }, + { url = "https://files.pythonhosted.org/packages/4b/aa/dabab50a2fb321a12ffe4668087e5d0f9b06286ccb260d345bf01c79b07c/rpds_py-0.25.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:6c72a4a8fab10bc96720ad40941bb471e3b1150fb8d62dab205d495511206cf1", size = 359693, upload-time = "2025-05-15T13:39:53.913Z" }, + { url = "https://files.pythonhosted.org/packages/11/3d/acda0095fe54ee6c553d222fb3d275506f8db4198b6a72a69eef826d63c1/rpds_py-0.25.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bb979162323f3534dce84b59f86e689a0761a2a300e0212bfaedfa80d4eb8100", size = 345911, upload-time = "2025-05-15T13:39:55.623Z" }, + { url = "https://files.pythonhosted.org/packages/db/f3/fba9b387077f9b305fce27fe22bdb731b75bfe208ae005fd09a127eced05/rpds_py-0.25.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35c8cb5dcf7d36d3adf2ae0730b60fb550a8feb6e432bee7ef84162a0d15714b", size = 387669, upload-time = "2025-05-15T13:39:57.103Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a7/b8dbcdc9a8f1e96b5abc58bdfc22f2845178279694a9294fe4feb66ae330/rpds_py-0.25.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:673ba018df5ae5e7b6c9a021d51ffe39c0ae1daa0041611ed27a0bca634b2d2e", size = 392202, upload-time = "2025-05-15T13:39:59.456Z" }, + { url = "https://files.pythonhosted.org/packages/60/60/2d46ad24207114cdb341490387d5a77c845827ac03f2a37182a19d072738/rpds_py-0.25.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16fb28d3a653f67c871a47c5ca0be17bce9fab8adb8bcf7bd09f3771b8c4d860", size = 450080, upload-time = "2025-05-15T13:40:01.131Z" }, + { url = "https://files.pythonhosted.org/packages/85/ae/b1966ca161942f2edf0b2c4fb448b88c19bdb37e982d0907c4b484eb0bbc/rpds_py-0.25.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12a84c3851f9e68633d883c01347db3cb87e6160120a489f9c47162cd276b0a5", size = 438189, upload-time = "2025-05-15T13:40:02.816Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b0/0a8bff40865e27fc8cd7bdf667958981794ccf5e7989890ae96c89112920/rpds_py-0.25.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b5f457afffb45d3804728a54083e31fbaf460e902e3f7d063e56d0d0814301e", size = 387925, upload-time = "2025-05-15T13:40:04.523Z" }, + { url = "https://files.pythonhosted.org/packages/a5/5d/62abbc77e18f9e67556ead54c84a7c662f39236b7a41cf1a39a24bf5e79f/rpds_py-0.25.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9442cbff21122e9a529b942811007d65eabe4182e7342d102caf119b229322c6", size = 417682, upload-time = "2025-05-15T13:40:06.879Z" }, + { url = "https://files.pythonhosted.org/packages/5d/eb/2f65e4332e3566d06c5ccad64441b1eaaf58a6c5999d533720f1f47d3118/rpds_py-0.25.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:383cf0d4288baf5a16812ed70d54ecb7f2064e255eb7fe42c38e926adeae4534", size = 565244, upload-time = "2025-05-15T13:40:08.598Z" }, + { url = "https://files.pythonhosted.org/packages/02/3a/ae5f68ab4879d6fbe3abec3139eab1664c3372d8b42864ab940a4940a61c/rpds_py-0.25.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0dcdee07ebf76223092666c72a9552db276fbe46b98830ecd1bb836cc98adc81", size = 590459, upload-time = "2025-05-15T13:40:10.375Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f6/ada6c3d9b803a9eb7bc9c8b3f3cebf7d779bbbb056cd7e3fc150e4c74c00/rpds_py-0.25.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5bbfbd9c74c4dd74815bd532bf29bedea6d27d38f35ef46f9754172a14e4c655", size = 558335, upload-time = "2025-05-15T13:40:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/68/9a/7d269e8f1bfe3143e699334ca0b578e16b37e6505bf10dca8c02aa8addc8/rpds_py-0.25.0-cp313-cp313t-win32.whl", hash = "sha256:90dbd2c42cb6463c07020695800ae8f347e7dbeff09da2975a988e467b624539", size = 218761, upload-time = "2025-05-15T13:40:16.043Z" }, + { url = "https://files.pythonhosted.org/packages/16/16/f5843b19b7bfd16d63b960cf4c646953010886cc62dd41b00854d77b0eed/rpds_py-0.25.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8c2ad59c4342a176cb3e0d5753e1c911eabc95c210fc6d0e913c32bf560bf012", size = 232634, upload-time = "2025-05-15T13:40:17.633Z" }, +] + +[[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 = "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.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" } +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" }, + { 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]] @@ -165,7 +365,25 @@ 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" } +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" }, +] + +[[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 = "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/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" }, + { 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 0f99c89676..a5064f6d38 100644 --- a/specs/signed_doc.json +++ b/specs/signed_doc.json @@ -1861,6 +1861,29 @@ "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#", diff --git a/specs/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json b/specs/signed_docs/docs/payload_schemas/proposal_submission_action.draft.example.json new file mode 100644 index 0000000000..747d3b6ec7 --- /dev/null +++ b/specs/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/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json b/specs/signed_docs/docs/payload_schemas/proposal_submission_action.final.example.json new file mode 100644 index 0000000000..bfbf15e59d --- /dev/null +++ b/specs/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/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json b/specs/signed_docs/docs/payload_schemas/proposal_submission_action.hide.example.json new file mode 100644 index 0000000000..e6f023094f --- /dev/null +++ b/specs/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/proposal_submission_action.cue b/specs/signed_docs/docs/proposal_submission_action.cue index 1db5557848..6d09f9a7fd 100644 --- a/specs/signed_docs/docs/proposal_submission_action.cue +++ b/specs/signed_docs/docs/proposal_submission_action.cue @@ -92,6 +92,33 @@ 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": { diff --git a/specs/signed_docs/payload.cue b/specs/signed_docs/payload.cue index f2dcbec41c..b7e1a379df 100644 --- a/specs/signed_docs/payload.cue +++ b/specs/signed_docs/payload.cue @@ -1,5 +1,19 @@ 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 @@ -7,4 +21,7 @@ _payload: { // 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] | *[] } From ebba46a15635426f7968a11233254d49ce55f483 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 19 Jun 2025 17:41:44 +0100 Subject: [PATCH 4/6] docs(docs): Added specification files for drep and voter delegation, drep profiles. Content of templates to be updated later --- .../08_concepts/signed_doc/diagrams/all.dot | 462 +++++ .../diagrams/category_parameters.dot | 32 + .../signed_doc/diagrams/profile.dot | 96 ++ .../signed_doc/diagrams/profile_template.dot | 87 + .../representative_category_profile.dot | 171 ++ ...presentative_category_profile_template.dot | 88 + .../diagrams/representative_profile.dot | 113 ++ .../representative_profile_template.dot | 88 + .../voter_representative_delegation.dot | 130 ++ .../08_concepts/signed_doc/docs/profile.md | 134 ++ .../signed_doc/docs/profile_template.md | 175 ++ .../docs/representative_category_profile.md | 209 +++ ...epresentative_category_profile_template.md | 185 ++ .../signed_doc/docs/representative_profile.md | 139 ++ .../docs/representative_profile_template.md | 202 +++ .../docs/voter_representative_delegation.md | 230 +++ .../08_concepts/signed_doc/metadata.md | 10 + .../08_concepts/signed_doc/types.md | 11 + specs/signed_doc.json | 1533 ++++++++++++++--- specs/signed_docs/docs/all.cue | 49 +- .../common_definitions.schema.json | 28 + .../profile_template.schema.json | 24 + ...tive_category_profile_template.schema.json | 32 + ...epresentative_profile_template.schema.json | 43 + ...oter_representative_delegation.schema.json | 27 + specs/signed_docs/docs/profile.cue | 52 + specs/signed_docs/docs/profile_template.cue | 41 + .../docs/representative_category_profile.cue | 73 + ...presentative_category_profile_template.cue | 46 + .../docs/representative_profile.cue | 58 + .../docs/representative_profile_template.cue | 34 + .../docs/voter_representative_delegation.cue | 64 + 32 files changed, 4422 insertions(+), 244 deletions(-) create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/profile.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/profile_template.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile_template.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile_template.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/diagrams/voter_representative_delegation.dot create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/profile.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md create mode 100644 docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md create mode 100644 specs/signed_docs/docs/payload_schemas/common_definitions.schema.json create mode 100644 specs/signed_docs/docs/payload_schemas/profile_template.schema.json create mode 100644 specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json create mode 100644 specs/signed_docs/docs/payload_schemas/representative_profile_template.schema.json create mode 100644 specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json create mode 100644 specs/signed_docs/docs/profile.cue create mode 100644 specs/signed_docs/docs/profile_template.cue create mode 100644 specs/signed_docs/docs/representative_category_profile.cue create mode 100644 specs/signed_docs/docs/representative_category_profile_template.cue create mode 100644 specs/signed_docs/docs/representative_profile.cue create mode 100644 specs/signed_docs/docs/representative_profile_template.cue create mode 100644 specs/signed_docs/docs/voter_representative_delegation.cue diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot index af9f30cf9e..4e18a642f2 100644 --- a/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/all.dot @@ -448,6 +448,126 @@ digraph "All" { ]; + "Profile Template" [ + id="Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Profile Template +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
1b70f611-518d-479e-be73-11b5e9cb68a5
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Profile" [ + id="Profile"; + label=< + + + + + + + + + + + + + + + + + + + + +
+ Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type1b70f611-518d-479e-be73-11b5e9cb68a5
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
templateProfile Template
+
+ > + ]; + + "Proposal Template" [ id="Proposal Template"; label=< @@ -963,10 +1083,346 @@ digraph "All" { ]; + "Representative Profile" [ + id="Representative Profile"; + label=< + + + + + + + + + + + + + + + + + + + + +
+ Representative Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typee3f2c1b4-7890-4abc-8def-2345678901ef
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
templateRepresentative Profile Template
+
+ > + ]; + + + "Representative Category Profile Template" [ + id="Representative Category Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Representative Category Profile Template +
+ + + + + +
content typeapplication/schema+json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
f1a2b3c4-1111-4abc-8def-2345678901aa
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Representative Category Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typef1a2b3c4-1111-4abc-8def-2345678901aa
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
refRepresentative Profile
+
+ + + + + +
templateRepresentative Category Profile Template
+
+ + + + + +
parametersCategory Parameters
+
+ > + ]; + + + "Representative Profile Template" [ + id="Representative Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Representative Profile Template +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
e3f2c1b4-7890-4abc-8def-2345678901ef
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Voter Representative Delegation" [ + id="Voter Representative Delegation"; + label=< + + + + + + + + + + + + + + + + + + + + + + + +
+ Voter Representative Delegation +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typef1a2b3c4-3333-4abc-8def-2345678901cc
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
refRepresentative Category Profile
+
+ + + + + +
parametersCategory Parameters
+
+ > + ]; + + "Campaign Parameters":"parameters":e -> "Brand Parameters":"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"] + "Profile":"template":e -> "Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] "Proposal":"template":e -> "Proposal 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="*"] @@ -982,4 +1438,10 @@ digraph "All" { "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"] + "Representative Category Profile":"ref":e -> "Representative Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Representative Category Profile":"template":e -> "Representative Category Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Representative Category Profile":"parameters":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"] + "Representative Profile":"template":e -> "Representative Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Voter Representative Delegation":"ref":e -> "Representative Category Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Voter Representative Delegation":"parameters":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.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/category_parameters.dot index b6a2aa470a..020b4dbc10 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 @@ -219,6 +219,36 @@ Relationships" ]; + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + +
+ Representative Category Profile +
+ > + ]; + + + "Voter Representative Delegation" [ + id="Voter Representative Delegation"; + label=< + + + + + +
+ Voter Representative Delegation +
+ > + ]; + + "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"] "Proposal":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"] @@ -228,4 +258,6 @@ Relationships" "Proposal Meta 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"] + "Representative Category Profile":"title":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"] + "Voter Representative Delegation":"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/profile.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/profile.dot new file mode 100644 index 0000000000..791767ab27 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/profile.dot @@ -0,0 +1,96 @@ +digraph "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="Profile Document Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Profile Template" [ + id="Profile Template"; + label=< + + + + + +
+ Profile Template +
+ > + ]; + + + "Profile" [ + id="Profile"; + label=< + + + + + + + + + + + + + + + + + + + + +
+ Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type1b70f611-518d-479e-be73-11b5e9cb68a5
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
templateProfile Template
+
+ > + ]; + + + "Profile":"template":e -> "Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/profile_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/profile_template.dot new file mode 100644 index 0000000000..68a6aeffda --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/profile_template.dot @@ -0,0 +1,87 @@ +digraph "Profile 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="Profile Template Document +Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Profile Template" [ + id="Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Profile Template +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
1b70f611-518d-479e-be73-11b5e9cb68a5
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Profile" [ + id="Profile"; + label=< + + + + + +
+ Profile +
+ > + ]; + + + "Profile":"title":e -> "Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile.dot new file mode 100644 index 0000000000..2eb5e6b20d --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile.dot @@ -0,0 +1,171 @@ +digraph "Representative Category 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="Representative Category +Profile Document Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Representative Profile" [ + id="Representative Profile"; + label=< + + + + + +
+ Representative Profile +
+ > + ]; + + + "Representative Category Profile Template" [ + id="Representative Category Profile Template"; + label=< + + + + + +
+ Representative Category Profile Template +
+ > + ]; + + + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Representative Category Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typef1a2b3c4-1111-4abc-8def-2345678901aa
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
refRepresentative Profile
+
+ + + + + +
templateRepresentative Category Profile Template
+
+ + + + + +
parametersCategory Parameters
+
+ > + ]; + + + "Voter Representative Delegation" [ + id="Voter Representative Delegation"; + label=< + + + + + +
+ Voter Representative Delegation +
+ > + ]; + + + subgraph cluster_system_parameters { + label = "System Parameters"; + color=blue + penwidth=20 + + "Category Parameters" [ + id="Category Parameters"; + label=< + + + + + +
+ Category Parameters +
+ > + ]; + + } + + "Representative Category Profile":"ref":e -> "Representative Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Representative Category Profile":"template":e -> "Representative Category Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Representative Category Profile":"parameters":e -> "Category Parameters" [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*", lhead="cluster_system_parameters"] + "Voter Representative Delegation":"title":e -> "Representative Category Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile_template.dot new file mode 100644 index 0000000000..6d45bac8cd --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_category_profile_template.dot @@ -0,0 +1,88 @@ +digraph "Representative Category Profile 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="Representative Category +Profile Template Document +Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Representative Category Profile Template" [ + id="Representative Category Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Representative Category Profile Template +
+ + + + + +
content typeapplication/schema+json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
f1a2b3c4-1111-4abc-8def-2345678901aa
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + +
+ Representative Category Profile +
+ > + ]; + + + "Representative Category Profile":"title":e -> "Representative Category Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile.dot new file mode 100644 index 0000000000..4a8e4e9428 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile.dot @@ -0,0 +1,113 @@ +digraph "Representative 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="Representative Profile +Document Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Representative Profile Template" [ + id="Representative Profile Template"; + label=< + + + + + +
+ Representative Profile Template +
+ > + ]; + + + "Representative Profile" [ + id="Representative Profile"; + label=< + + + + + + + + + + + + + + + + + + + + +
+ Representative Profile +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typee3f2c1b4-7890-4abc-8def-2345678901ef
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
templateRepresentative Profile Template
+
+ > + ]; + + + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + +
+ Representative Category Profile +
+ > + ]; + + + "Representative Profile":"template":e -> "Representative Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Representative Category Profile":"title":e -> "Representative Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile_template.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile_template.dot new file mode 100644 index 0000000000..3484aff65e --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/representative_profile_template.dot @@ -0,0 +1,88 @@ +digraph "Representative Profile 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="Representative Profile +Template Document +Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Representative Profile Template" [ + id="Representative Profile Template"; + label=< + + + + + + + + + + + + + + + + + +
+ Representative Profile Template +
+ + + + + +
content typeapplication/json
+
+ + + + + +
type0ce8ab38-9258-4fbc-a62e-7faa6e58318f
e3f2c1b4-7890-4abc-8def-2345678901ef
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ > + ]; + + + "Representative Profile" [ + id="Representative Profile"; + label=< + + + + + +
+ Representative Profile +
+ > + ]; + + + "Representative Profile":"title":e -> "Representative Profile Template":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] +} diff --git a/docs/src/architecture/08_concepts/signed_doc/diagrams/voter_representative_delegation.dot b/docs/src/architecture/08_concepts/signed_doc/diagrams/voter_representative_delegation.dot new file mode 100644 index 0000000000..2c7dbd319b --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/diagrams/voter_representative_delegation.dot @@ -0,0 +1,130 @@ +digraph "Voter Representative 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="Voter Representative +Delegation Document +Relationships" + fontcolor="#1d71b8" + fontsize=50 + compound=true + + + + "Representative Category Profile" [ + id="Representative Category Profile"; + label=< + + + + + +
+ Representative Category Profile +
+ > + ]; + + + "Voter Representative Delegation" [ + id="Voter Representative Delegation"; + label=< + + + + + + + + + + + + + + + + + + + + + + + +
+ Voter Representative Delegation +
+ + + + + +
content typeapplication/json
+
+ + + + + +
typef1a2b3c4-3333-4abc-8def-2345678901cc
+
+ + + + + +
idDocument Id
+
+ + + + + +
verDocument Ver
+
+ + + + + +
refRepresentative Category Profile
+
+ + + + + +
parametersCategory Parameters
+
+ > + ]; + + + subgraph cluster_system_parameters { + label = "System Parameters"; + color=blue + penwidth=20 + + "Category Parameters" [ + id="Category Parameters"; + label=< + + + + + +
+ Category Parameters +
+ > + ]; + + } + + "Voter Representative Delegation":"ref":e -> "Representative Category Profile":"title":w [dir=forward, penwidth=6, color="#29235c", headlabel="1", taillabel="*"] + "Voter Representative Delegation":"parameters":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/docs/profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md new file mode 100644 index 0000000000..af53961018 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md @@ -0,0 +1,134 @@ +# Profile + +## Description + +## Profile Document + +A profile document for a Catalyst user containing basic user information. + + + +```graphviz dot profile.dot.svg +{{ include_file('./../diagrams/profile.dot', indent=4) }} +``` + + + +### Validation + +The profile must include both a name and a bio. No additional validation beyond schema and required fields. + +### Business Logic + +#### Front End + +Display and allow editing of profile fields for the user. + +#### Back End + +Validate profile data and store in the system. + +## [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 | `1b70f611-518d-479e-be73-11b5e9cb68a5` | + +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) 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 | [Profile Template](profile_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. + +## Payload + +The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template. + +## 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 + +[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/profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md new file mode 100644 index 0000000000..522cf66cf9 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md @@ -0,0 +1,175 @@ +# Profile Template + +## Description + +## Profile Template Document + +Defines the allowed payload contents and constraints for a generic user profile. + + + +```graphviz dot profile_template.dot.svg +{{ include_file('./../diagrams/profile_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/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`,
`1b70f611-518d-479e-be73-11b5e9cb68a5` | + +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) Validation + +The document version must always be >= the document ID. + +## Payload + +[JSON Schema] document which defines the valid contents of a profile document. + +### Schema + + +??? abstract + + [JSON Schema] document which defines the valid contents of a profile document. + + ```json + { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/profile_template.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "description": "Schema for a profile document template for any Catalyst actor.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "bio" + ], + "title": "Profile Template Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } + ``` + + + +## Signers + +The following admin roles may sign documents of this type: + +* Brand Admin + +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 + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[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/representative_category_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md new file mode 100644 index 0000000000..536c4588ed --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md @@ -0,0 +1,209 @@ +# Representative Category Profile + +## Description + + ## Representative Category Profile Document + + A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. + The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. + + The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. + + The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation. + + + +```graphviz dot representative_category_profile.dot.svg +{{ include_file('./../diagrams/representative_category_profile.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 'Category Parameters' document. + - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document. + - The payload MUST be valid against the [JSON schema] defined in the referenced template. + +### Business Logic + +#### Front End + + - Allows a Representative to create or update their profile for a category. + - The status is set to 'active' when created and the Representative is then discoverable for delegation. + - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category. + +#### Back End + + - The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. + - The system will only consider Representatives with an 'active' status as eligible for delegation. + +## [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 | `f1a2b3c4-1111-4abc-8def-2345678901aa` | + +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) 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 | [Representative Profile](representative_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 | [Representative Category Profile Template](representative_category_profile_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) + + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [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 + +The Representative's profile data for a specific category. Its structure is defined by the referenced template document. + It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. + +## 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]: https://json-schema.org/draft-07 +[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/representative_category_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md new file mode 100644 index 0000000000..844ad154e6 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md @@ -0,0 +1,185 @@ +# Representative Category Profile Template + +## Description + + ## Representative Category Profile Template Document + + Defines the allowed payload contents and constraints for a Representative's category-specific profile. + This template is created by an Admin to enforce a consistent structure for all Representatives within a given category. + + + +```graphviz dot representative_category_profile_template.dot.svg +{{ include_file('./../diagrams/representative_category_profile_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`,
`f1a2b3c4-1111-4abc-8def-2345678901aa` | + +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) Validation + +The document version must always be >= the document ID. + +## Payload + +[JSON Schema] document which defines the valid contents of a Representative Category Profile document. +The schema MUST include a 'status' field to indicate if the Representative is active or withdrawn from the category. + +### Schema + + +??? abstract + + [JSON Schema] document which defines the valid contents of a Representative Category Profile document. + The schema MUST include a 'status' field to indicate if the Representative is active or withdrawn from the category. + + ```json + { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "definitions": { + "status": { + "description": "The Representative's status in this category. 'active' means they are participating, 'revoked' means they have withdrawn.", + "enum": [ + "active", + "revoked" + ], + "type": "string" + } + }, + "description": "This schema is defined by an Admin to specify the required properties for a user opting in as a Representative within a specific campaign category. It outlines the structure of a Representative's profile for that category and supports the addition of custom properties as needed by the Admin. The status field is mandatory and cannot be removed or modified by the Admin.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "status": { + "$ref": "#/definitions/status" + } + }, + "required": [ + "status" + ], + "title": "Representative Category Profile Template Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } + ``` + + + +## Signers + +The following admin roles may sign documents of this type: + +* Brand Admin +* Campaign Admin + +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 + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[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/representative_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md new file mode 100644 index 0000000000..1d42d1e926 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md @@ -0,0 +1,139 @@ +# Representative Profile + +## Description + +## Representative Profile Document + +A Representative-specific profile, extending the minimal profile with Representative-specific fields. + + + +```graphviz dot representative_profile.dot.svg +{{ include_file('./../diagrams/representative_profile.dot', indent=4) }} +``` + + + +### Validation + + - The signer MUST be a registered 'Representative'. + - The payload MUST be valid against the [JSON schema] defined in the referenced 'Representative 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 identity across all funds and categories. + +#### Back End + +- Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system. +- This global profile is the foundational document referenced by all of the Representative's category-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 | `e3f2c1b4-7890-4abc-8def-2345678901ef` | + +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) 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 | [Representative Profile Template](representative_profile_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. + +## Payload + +The Representative profile payload contains all base profile fields and Representative-specific fields. +Its structure is defined by the referenced Representative Profile Template. + +## 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]: https://json-schema.org/draft-07 +[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/representative_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md new file mode 100644 index 0000000000..1bf64e4a91 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md @@ -0,0 +1,202 @@ +# Representative Profile Template + +## Description + + ## Representative Profile Template Document + + Defines the allowed payload contents and constraints for a Representative profile. + + + +```graphviz dot representative_profile_template.dot.svg +{{ include_file('./../diagrams/representative_profile_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/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`,
`e3f2c1b4-7890-4abc-8def-2345678901ef` | + +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) Validation + +The document version must always be >= the document ID. + +## Payload + +[JSON Schema] document which defines the valid contents of a Representative profile document. + +### Schema + + +??? abstract + + [JSON Schema] document which defines the valid contents of a Representative profile document. + + ```json + { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/drep_profile_template.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "description": "Schema for a Representative profile document template, extending the base profile with Representative-specific fields as defined by the Admin.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "avatar": { + "$ref": "common_definitions.schema.json#/definitions/ipfsUrl" + }, + "avatar_required": { + "enum": [ + "yes", + "optional", + "excluded" + ], + "type": "string" + }, + "bio": { + "type": "string" + }, + "name": { + "type": "string" + }, + "social_links": { + "items": { + "$ref": "common_definitions.schema.json#/definitions/url" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "website": { + "$ref": "common_definitions.schema.json#/definitions/url" + } + }, + "required": [ + "name", + "bio", + "avatar", + "website", + "social_links", + "tags", + "avatar_required" + ], + "title": "Representative Profile Template Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } + ``` + + + +## 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 + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[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/voter_representative_delegation.md b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md new file mode 100644 index 0000000000..937d61ed05 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md @@ -0,0 +1,230 @@ +# Voter Representative Delegation + +## Description + + ## Voter Representative Delegation Document + + Captures that a voter (the signer) has delegated to a Representative for a specific category. + The document this refers to (`ref`) is the Representative's Category Profile. + The category itself is specified in the [`parameters`](../metadata.md#parameters) metadata. + + + +```graphviz dot voter_representative_delegation.dot.svg +{{ include_file('./../diagrams/voter_representative_delegation.dot', indent=4) }} +``` + + + +### Validation + + The payload must contain a 'status' field, which must be either 'active' or 'revoked'. + The Category id for the Representative's Category Profile and as specified in the metadata must match. + +### Business Logic + +#### Front End + + Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked'). + +#### Back End + + Validate the delegation action and update the voter's delegation state for the given category and Representative. + +## [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 | `f1a2b3c4-3333-4abc-8def-2345678901cc` | + +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) 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 | [Representative Category Profile](representative_category_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. + +### [`parameters`](../metadata.md#parameters) + + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [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 + +A minimal payload indicating the intended status of the delegation. + 'active' creates or affirms the delegation. + 'revoked' withdraws the delegation. + +### Schema + + +??? abstract + + A minimal payload indicating the intended status of the delegation. + 'active' creates or affirms the delegation. + 'revoked' withdraws the delegation. + + ```json + { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "description": "This payload is submitted when a voter delegates to a Representative, with the voter as the signer and the Representative\u2019s category profile as the referenced document; to revoke the delegation, the voter can publish again with the status set to revoked.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "status": { + "description": "The status of the delegation. 'active' signifies delegation (set by default), 'revoked' signifies withdrawal of delegation.", + "enum": [ + "active", + "revoked" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "title": "Voter Representative Delegation Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } + ``` + + + +## 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 diff --git a/docs/src/architecture/08_concepts/signed_doc/metadata.md b/docs/src/architecture/08_concepts/signed_doc/metadata.md index 8daa80ac97..a4310bfac4 100644 --- a/docs/src/architecture/08_concepts/signed_doc/metadata.md +++ b/docs/src/architecture/08_concepts/signed_doc/metadata.md @@ -208,6 +208,13 @@ The document version must always be >= the document ID. | | [Campaign Parameters](./docs/campaign_parameters.md) | | | [Category Parameters](./docs/category_parameters.md) | | | [Decision Parameters](./docs/decision_parameters.md) | +| | [Profile](./docs/profile.md) | +| | [Profile Template](./docs/profile_template.md) | +| | [Representative Profile Template](./docs/representative_profile_template.md) | +| | [Representative Category Profile Template](./docs/representative_category_profile_template.md) | +| | [Representative Profile](./docs/representative_profile.md) | +| | [Representative Category Profile](./docs/representative_category_profile.md) | +| | [Voter Representative Delegation](./docs/voter_representative_delegation.md) | Reference to a Linked Document or Documents. This is the primary hierarchical reference to a related document. @@ -252,6 +259,9 @@ The following must be true for a valid reference: | | [Proposal Template](./docs/proposal_template.md) | | | [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) | | | [Proposal Comment Template](./docs/proposal_comment_template.md) | +| | [Profile Template](./docs/profile_template.md) | +| | [Representative Profile Template](./docs/representative_profile_template.md) | +| | [Representative Category Profile Template](./docs/representative_category_profile_template.md) | Reference to the template used to create and/or validate this document. diff --git a/docs/src/architecture/08_concepts/signed_doc/types.md b/docs/src/architecture/08_concepts/signed_doc/types.md index 35c823f1a5..008e5b57f4 100644 --- a/docs/src/architecture/08_concepts/signed_doc/types.md +++ b/docs/src/architecture/08_concepts/signed_doc/types.md @@ -13,9 +13,13 @@ All Document Types are defined by composing these base document types: | Comment | `b679ded3-0e7c-41ba-89f8-da62a17898ea` | `37(h'b679ded30e7c41ba89f8da62a17898ea')` | | Decision | `788ff4c6-d65a-451f-bb33-575fe056b411` | `37(h'788ff4c6d65a451fbb33575fe056b411')` | | ModerationAction | `a5d232b8-5e03-4117-9afd-be32b878fcdd` | `37(h'a5d232b85e0341179afdbe32b878fcdd')` | +| Profile | `1b70f611-518d-479e-be73-11b5e9cb68a5` | `37(h'1b70f611518d479ebe7311b5e9cb68a5')` | | Proposal | `7808d2ba-d511-40af-84e8-c0d1625fdfdc` | `37(h'7808d2bad51140af84e8c0d1625fdfdc')` | +| RepresentativeCategoryProfile | `f1a2b3c4-1111-4abc-8def-2345678901aa` | `37(h'f1a2b3c411114abc8def2345678901aa')` | +| RepresentativeProfile | `e3f2c1b4-7890-4abc-8def-2345678901ef` | `37(h'e3f2c1b478904abc8def2345678901ef')` | | SubmissionAction | `78927329-cfd9-4ea1-9c71-0e019b126a65` | `37(h'78927329cfd94ea19c710e019b126a65')` | | Template | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f` | `37(h'0ce8ab3892584fbca62e7faa6e58318f')` | +| VoterRepresentativeDelegation | `f1a2b3c4-3333-4abc-8def-2345678901cc` | `37(h'f1a2b3c433334abc8def2345678901cc')` | ## Document Types @@ -29,6 +33,8 @@ All Defined Document Types | [Category Parameters](./docs/category_parameters.md) | Category | [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')] | +| [Profile](./docs/profile.md) | Profile | [37(h'1b70f611518d479ebe7311b5e9cb68a5')] | +| [Profile Template](./docs/profile_template.md) | Template/Profile | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'1b70f611518d479ebe7311b5e9cb68a5')] | | [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')] | @@ -37,6 +43,11 @@ All Defined Document Types | [Proposal Moderation Action](./docs/proposal_moderation_action.md) | Action/Proposal/ModerationAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'),
37(h'7808d2bad51140af84e8c0d1625fdfdc'),
37(h'a5d232b85e0341179afdbe32b878fcdd')] | | [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')] | +| [Representative Category Profile](./docs/representative_category_profile.md) | RepresentativeCategoryProfile | [37(h'f1a2b3c411114abc8def2345678901aa')] | +| [Representative Category Profile Template](./docs/representative_category_profile_template.md) | Template/RepresentativeCategoryProfile | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'f1a2b3c411114abc8def2345678901aa')] | +| [Representative Profile](./docs/representative_profile.md) | RepresentativeProfile | [37(h'e3f2c1b478904abc8def2345678901ef')] | +| [Representative Profile Template](./docs/representative_profile_template.md) | Template/RepresentativeProfile | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'e3f2c1b478904abc8def2345678901ef')] | +| [Voter Representative Delegation](./docs/voter_representative_delegation.md) | VoterRepresentativeDelegation | [37(h'f1a2b3c433334abc8def2345678901cc')] | ## Document Relationship Hierarchy diff --git a/specs/signed_doc.json b/specs/signed_doc.json index a5064f6d38..aff8ba9e5e 100644 --- a/specs/signed_doc.json +++ b/specs/signed_doc.json @@ -11,9 +11,13 @@ "Comment": "b679ded3-0e7c-41ba-89f8-da62a17898ea", "Decision": "788ff4c6-d65a-451f-bb33-575fe056b411", "ModerationAction": "a5d232b8-5e03-4117-9afd-be32b878fcdd", + "Profile": "1b70f611-518d-479e-be73-11b5e9cb68a5", "Proposal": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "RepresentativeCategoryProfile": "f1a2b3c4-1111-4abc-8def-2345678901aa", + "RepresentativeProfile": "e3f2c1b4-7890-4abc-8def-2345678901ef", "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65", - "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f" + "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "VoterRepresentativeDelegation": "f1a2b3c4-3333-4abc-8def-2345678901cc" }, "cddlDefinitions": { "COSE_Document_Header_Map": { @@ -930,15 +934,15 @@ } ] }, - "Proposal": { + "Profile": { "authors": { - "Steven Johnson": "steven.johnson@iohk.io" + "Neil McAuliffe": "neil.mcauliffe@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." + "back_end": "Validate profile data and store in the system.", + "front_end": "Display and allow editing of profile fields for the user." }, - "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.", + "description": "## Profile Document\n\nA profile document for a Catalyst user containing basic user information.", "headers": { "content type": { "coseLabel": 3, @@ -962,7 +966,7 @@ "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": { @@ -976,16 +980,7 @@ "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" - ], + "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." }, "ref": { @@ -1006,7 +1001,7 @@ "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": { @@ -1023,7 +1018,7 @@ "linked_refs": null, "multiple": false, "required": "yes", - "type": "Proposal Template", + "type": "Profile 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": { @@ -1043,43 +1038,35 @@ }, "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": "The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template." }, "signers": { "roles": { "user": [ - "Proposer" + "Registered" ] }, "update": { - "author": true, - "collaborators": true + "author": true } }, "type": [ - "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + "1b70f611-518d-479e-be73-11b5e9cb68a5" ], - "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.", + "validation": "The profile must include both a name and a bio. No additional validation beyond schema and required fields.", "versions": [ { - "changes": "* First Published Version", - "modified": "2025-04-04", + "changes": "\t* First Published Version", + "modified": "2025-06-19", "version": "0.01" - }, - { - "changes": "* Use generalized parameters.", - "modified": "2025-05-05", - "version": "0.03" } ] }, - "Proposal Comment": { - "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." + "Profile Template": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, - "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": "## Profile Template Document\n\nDefines the allowed payload contents and constraints for a generic user profile.", "headers": { "content type": { "coseLabel": 3, @@ -1117,61 +1104,42 @@ "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" - ], + "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." }, "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", - "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": { @@ -1191,10 +1159,44 @@ }, "notes": [], "payload": { - "description": "JSON Document which must validate against the referenced template." + "description": "JSON Schema document which defines the valid contents of a profile document.", + "schema": { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/profile_template.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "description": "Schema for a profile document template for any Catalyst actor.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "bio" + ], + "title": "Profile Template Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } }, "signers": { "roles": { + "admin": [ + "Brand Admin" + ], "user": [ "Registered" ] @@ -1204,33 +1206,33 @@ } }, "type": [ - "b679ded3-0e7c-41ba-89f8-da62a17898ea", - "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "1b70f611-518d-479e-be73-11b5e9cb68a5" ], - "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", + "changes": "\t* First Published Version", + "modified": "2025-06-19", "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.", + "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, "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", @@ -1247,7 +1249,7 @@ "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": { @@ -1261,7 +1263,9 @@ "description": "A reference to the Parameters Document this document lies under.", "exclusive": null, "format": "Document Reference", - "linked_refs": null, + "linked_refs": [ + "template" + ], "multiple": false, "required": "yes", "type": [ @@ -1289,7 +1293,7 @@ "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": { @@ -1303,7 +1307,10 @@ "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 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": { @@ -1323,27 +1330,23 @@ }, "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": "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": { - "admin": [ - "Root Admin", - "Brand Admin" - ], - "user": [] + "user": [ + "Proposer" + ] }, "update": { - "author": true + "author": true, + "collaborators": true } }, "type": [ - "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", - "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", - "b679ded3-0e7c-41ba-89f8-da62a17898ea", "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", @@ -1357,16 +1360,20 @@ } ] }, - "Proposal Comment Template": { + "Proposal Comment": { "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.", + "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.", "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", @@ -1397,7 +1404,10 @@ "description": "A reference to the Parameters Document this document lies under.", "exclusive": null, "format": "Document Reference", - "linked_refs": null, + "linked_refs": [ + "ref", + "template" + ], "multiple": false, "required": "yes", "type": [ @@ -1411,28 +1421,34 @@ "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": "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": { @@ -1441,8 +1457,8 @@ "format": "Document Reference", "linked_refs": null, "multiple": false, - "required": "optional", - "type": "Proposal Comment Meta Template", + "required": "yes", + "type": "Proposal Comment 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": { @@ -1462,25 +1478,23 @@ }, "notes": [], "payload": { - "description": "JSON Schema document which defines the content of the Proposal Comments." + "description": "JSON Document which must validate against the referenced template." }, "signers": { "roles": { - "admin": [ - "Brand Admin", - "Campaign Admin" - ], - "user": [] + "user": [ + "Registered" + ] }, "update": { "author": true } }, "type": [ - "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", "b679ded3-0e7c-41ba-89f8-da62a17898ea", "7808d2ba-d511-40af-84e8-c0d1625fdfdc" ], + "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", @@ -1494,9 +1508,9 @@ } ] }, - "Proposal Meta Template": { + "Proposal Comment Meta 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": "## 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, @@ -1596,7 +1610,7 @@ }, "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.", + "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" }, "signers": { @@ -1614,6 +1628,7 @@ "type": [ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "b679ded3-0e7c-41ba-89f8-da62a17898ea", "7808d2ba-d511-40af-84e8-c0d1625fdfdc" ], "versions": [ @@ -1629,16 +1644,16 @@ } ] }, - "Proposal Moderation Action": { + "Proposal Comment Template": { "authors": {}, - "description": "A Moderation action performed on a Proposal.", + "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.", "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", @@ -1669,17 +1684,21 @@ "description": "A reference to the Parameters Document this document lies under.", "exclusive": null, "format": "Document Reference", - "required": "excluded", + "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." }, "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": { @@ -1707,7 +1726,10 @@ "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": "optional", + "type": "Proposal Comment Meta 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": { @@ -1726,20 +1748,285 @@ } }, "notes": [], + "payload": { + "description": "JSON Schema document which defines the content of the Proposal Comments." + }, "signers": { "roles": { - "user": [ - "Registered" - ] + "admin": [ + "Brand Admin", + "Campaign Admin" + ], + "user": [] }, "update": { "author": true } }, "type": [ - "5e60e623-ad02-4a1b-a1ac-406db978ee48", - "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "a5d232b8-5e03-4117-9afd-be32b878fcdd" + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "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" + } + ] + }, + "Proposal Meta 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.", + "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": { + "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." + }, + "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, + "format": "Document Ver", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "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" + }, + "signers": { + "roles": { + "admin": [ + "Root Admin", + "Brand Admin" + ], + "user": [] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "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" + } + ] + }, + "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": { + "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." + }, + "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", + "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, + "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": [ { @@ -1755,7 +2042,772 @@ "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.", + "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": { + "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" + ], + "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." + }, + "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, + "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", + "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, + "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" + } + ] + }, + "Proposal 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.", + "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": { + "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" + ], + "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." + }, + "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", + "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." + } + }, + "notes": [], + "payload": { + "description": "JSON Schema document which defines the valid contents of a proposal document." + }, + "signers": { + "roles": { + "admin": [ + "Brand Admin", + "Campaign 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" + } + ] + }, + "Representative Category Profile": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@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 with an 'active' status as eligible for delegation.", + "front_end": " - Allows a Representative to create or update their profile for a category.\n - The status is set to 'active' when created and the Representative is then discoverable for delegation.\n - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category." + }, + "description": " ## Representative Category Profile Document\n\n A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\n The presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n \n The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n \n The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation.", + "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": { + "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": "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." + }, + "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": "Representative 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.", + "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": "yes", + "type": "Representative Category Profile 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, + "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 category. Its structure is defined by the referenced template document.\n It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation." + }, + "signers": { + "roles": { + "user": [ + "Representative" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "f1a2b3c4-1111-4abc-8def-2345678901aa" + ], + "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 'Category Parameters' document.\n - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document.\n - The payload MUST be valid against the JSON schema defined in the referenced template.", + "versions": [ + { + "changes": "* First Published Version", + "modified": "2025-06-19", + "version": "0.01" + } + ] + }, + "Representative Category Profile Template": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + }, + "description": " ## Representative Category Profile Template Document\n\n Defines the allowed payload contents and constraints for a Representative's category-specific profile.\n This template is created by an Admin to enforce a consistent structure for all Representatives within a given category.", + "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": { + "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." + }, + "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, + "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 of a Representative Category Profile document.\nThe schema MUST include a 'status' field to indicate if the Representative is active or withdrawn from the category.", + "schema": { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "definitions": { + "status": { + "description": "The Representative's status in this category. 'active' means they are participating, 'revoked' means they have withdrawn.", + "enum": [ + "active", + "revoked" + ], + "type": "string" + } + }, + "description": "This schema is defined by an Admin to specify the required properties for a user opting in as a Representative within a specific campaign category. It outlines the structure of a Representative's profile for that category and supports the addition of custom properties as needed by the Admin. The status field is mandatory and cannot be removed or modified by the Admin.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "status": { + "$ref": "#/definitions/status" + } + }, + "required": [ + "status" + ], + "title": "Representative Category Profile Template Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } + }, + "signers": { + "roles": { + "admin": [ + "Brand Admin", + "Campaign Admin" + ], + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "f1a2b3c4-1111-4abc-8def-2345678901aa" + ], + "versions": [ + { + "changes": " * First Published Version", + "modified": "2025-06-19", + "version": "0.01" + } + ] + }, + "Representative Profile": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + }, + "business_logic": { + "back_end": "- Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system.\n- This global profile is the foundational document referenced by all of the Representative's category-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 identity across all funds and categories." + }, + "description": "## Representative Profile Document\n\nA Representative-specific profile, extending the minimal profile with Representative-specific fields.", + "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": { + "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." + }, + "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": "yes", + "type": "Representative Profile 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, + "format": "Document Ver", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "notes": [], + "payload": { + "description": "The Representative profile payload contains all base profile fields and Representative-specific fields.\nIts structure is defined by the referenced Representative Profile Template." + }, + "signers": { + "roles": { + "user": [ + "Representative" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "e3f2c1b4-7890-4abc-8def-2345678901ef" + ], + "validation": " - The signer MUST be a registered 'Representative'.\n - The payload MUST be valid against the JSON schema defined in the referenced 'Representative Profile Template'.", + "versions": [ + { + "changes": "* First Published Version", + "modified": "2025-06-19", + "version": "0.01" + } + ] + }, + "Representative Profile Template": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + }, + "description": " ## Representative Profile Template Document\n\n Defines the allowed payload contents and constraints for a Representative profile.", "headers": { "content type": { "coseLabel": 3, @@ -1793,26 +2845,14 @@ "description": "A reference to the Parameters Document this document lies under.", "exclusive": null, "format": "Document Reference", - "linked_refs": [ - "ref" - ], - "multiple": false, - "required": "yes", - "type": [ - "Brand Parameters", - "Campaign Parameters", - "Category Parameters" - ], + "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." }, "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, - "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": { @@ -1860,46 +2900,12 @@ }, "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" - } - ], + "description": "JSON Schema document which defines the valid contents of a Representative profile document.", "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", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/drep_profile_template.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.", + "description": "Schema for a Representative profile document template, extending the base profile with Representative-specific fields as defined by the Admin.", "maintainers": [ { "name": "Catalyst Team", @@ -1907,63 +2913,95 @@ } ], "properties": { - "action": { - "$ref": "#/definitions/action" + "avatar": { + "$ref": "common_definitions.schema.json#/definitions/ipfsUrl" + }, + "avatar_required": { + "enum": [ + "yes", + "optional", + "excluded" + ], + "type": "string" + }, + "bio": { + "type": "string" + }, + "name": { + "type": "string" + }, + "social_links": { + "items": { + "$ref": "common_definitions.schema.json#/definitions/url" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "website": { + "$ref": "common_definitions.schema.json#/definitions/url" } }, "required": [ - "action" + "name", + "bio", + "avatar", + "website", + "social_links", + "tags", + "avatar_required" ], - "title": "Proposal Submission Action Payload Schema", + "title": "Representative Profile Template Payload Schema", "type": "object", "x-changelog": { - "2025-03-01": [ + "2025-06-19": [ "First Version Created." ] } } }, "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" + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "e3f2c1b4-7890-4abc-8def-2345678901ef" ], - "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", + "changes": " * First Published Version", + "modified": "2025-06-19", "version": "0.01" - }, - { - "changes": "* Use generalized parameters.", - "modified": "2025-05-05", - "version": "0.03" } ] }, - "Proposal 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.", + "Voter Representative Delegation": { + "authors": { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + }, + "business_logic": { + "back_end": " Validate the delegation action and update the voter's delegation state for the given category and Representative.", + "front_end": " Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked')." + }, + "description": " ## Voter Representative Delegation Document\n\n Captures that a voter (the signer) has delegated to a Representative for a specific category.\n The document this refers to (`ref`) is the Representative's Category Profile.\n The category itself is specified in the `parameters` metadata.", "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", @@ -1994,23 +3032,20 @@ "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": [ - "Brand Parameters", - "Campaign Parameters", - "Category Parameters" - ], + "type": "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." }, "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": "Representative Category 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": { @@ -2038,10 +3073,7 @@ "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": { @@ -2061,34 +3093,59 @@ }, "notes": [], "payload": { - "description": "JSON Schema document which defines the valid contents of a proposal document." + "description": " A minimal payload indicating the intended status of the delegation.\n 'active' creates or affirms the delegation.\n 'revoked' withdraws the delegation.", + "schema": { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "description": "This payload is submitted when a voter delegates to a Representative, with the voter as the signer and the Representative’s category profile as the referenced document; to revoke the delegation, the voter can publish again with the status set to revoked.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "status": { + "description": "The status of the delegation. 'active' signifies delegation (set by default), 'revoked' signifies withdrawal of delegation.", + "enum": [ + "active", + "revoked" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "title": "Voter Representative Delegation Payload Schema", + "type": "object", + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + } + } }, "signers": { "roles": { - "admin": [ - "Brand Admin", - "Campaign Admin" - ], - "user": [] + "user": [ + "Registered" + ] }, "update": { "author": true } }, "type": [ - "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", - "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + "f1a2b3c4-3333-4abc-8def-2345678901cc" ], + "validation": " The payload must contain a 'status' field, which must be either 'active' or 'revoked'.\n The Category id for the Representative's Category Profile and as specified in the metadata must match. ", "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" } ] } @@ -2191,7 +3248,14 @@ "Brand Parameters", "Campaign Parameters", "Category Parameters", - "Decision Parameters" + "Decision Parameters", + "Profile", + "Profile Template", + "Representative Profile Template", + "Representative Category Profile Template", + "Representative Profile", + "Representative Category Profile", + "Voter Representative 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." }, @@ -2232,7 +3296,10 @@ "Proposal Meta Template", "Proposal Template", "Proposal Comment Meta Template", - "Proposal Comment Template" + "Proposal Comment Template", + "Profile Template", + "Representative Profile Template", + "Representative Category Profile 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." }, diff --git a/specs/signed_docs/docs/all.cue b/specs/signed_docs/docs/all.cue index a0859b3102..e9eaea2441 100644 --- a/specs/signed_docs/docs/all.cue +++ b/specs/signed_docs/docs/all.cue @@ -7,16 +7,20 @@ import ( // 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" + "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" + "Profile": "1b70f611-518d-479e-be73-11b5e9cb68a5" + "RepresentativeProfile": "e3f2c1b4-7890-4abc-8def-2345678901ef" + "RepresentativeCategoryProfile": "f1a2b3c4-1111-4abc-8def-2345678901aa" + "VoterRepresentativeDelegation": "f1a2b3c4-3333-4abc-8def-2345678901cc" } // Source of truth for ALL Document Types and their matching UUID's. @@ -78,7 +82,30 @@ _allDocs: { "Decision Parameters": [ _allDocTypes["Decision"], ] - + "Profile": [ + _allDocTypes["Profile"], + ] + "Profile Template": [ + _allDocTypes["Template"], + _allDocTypes["Profile"], + ] + "Representative Profile Template": [ + _allDocTypes["Template"], + _allDocTypes["RepresentativeProfile"], + ] + "Representative Category Profile Template": [ + _allDocTypes["Template"], + _allDocTypes["RepresentativeCategoryProfile"], + ] + "Representative Profile": [ + _allDocTypes["RepresentativeProfile"], + ] + "Representative Category Profile": [ + _allDocTypes["RepresentativeCategoryProfile"], + ] + "Voter Representative Delegation": [ + _allDocTypes["VoterRepresentativeDelegation"], + ] } // Document Cluster Definition diff --git a/specs/signed_docs/docs/payload_schemas/common_definitions.schema.json b/specs/signed_docs/docs/payload_schemas/common_definitions.schema.json new file mode 100644 index 0000000000..5234074662 --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/common_definitions.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/common_definitions.schema.json", + "title": "Common Definitions", + "description": "Commonly used data type definitions for signed document schemas.", + "definitions": { + "url": { + "type": "string", + "pattern": "^https?://.+" + }, + "ipfsUrl": { + "type": "string", + "pattern": "^ipfs://.+" + }, + "uuid": { + "type": "string", + "format": "uuid" + }, + "date_yyyymmdd": { + "type": "string", + "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$" + }, + "timestamp_rfc3339": { + "type": "string", + "format": "date-time" + } + } +} \ No newline at end of file diff --git a/specs/signed_docs/docs/payload_schemas/profile_template.schema.json b/specs/signed_docs/docs/payload_schemas/profile_template.schema.json new file mode 100644 index 0000000000..d7a58a5e22 --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/profile_template.schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/profile_template.schema.json", + "title": "Profile Template Payload Schema", + "description": "Schema for a profile document template for any Catalyst actor.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + }, + "type": "object", + "additionalProperties": false, + "properties": { + "name": { "type": "string" }, + "bio": { "type": "string" } + }, + "required": ["name", "bio"] +} \ No newline at end of file diff --git a/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json b/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json new file mode 100644 index 0000000000..6f5a257632 --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/representative_category_profile_template.schema.json", + "title": "Representative Category Profile Template Payload Schema", + "description": "This schema is defined by an Admin to specify the required properties for a user opting in as a Representative within a specific campaign category. It outlines the structure of a Representative's profile for that category and supports the addition of custom properties as needed by the Admin. The status field is mandatory and cannot be removed or modified by the Admin.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + }, + "type": "object", + "additionalProperties": true, + "definitions": { + "status": { + "type": "string", + "enum": ["active", "revoked"], + "description": "The Representative's status in this category. 'active' means they are participating, 'revoked' means they have withdrawn." + } + }, + "properties": { + "status": { + "$ref": "#/definitions/status" + } + }, + "required": ["status"] +} \ No newline at end of file diff --git a/specs/signed_docs/docs/payload_schemas/representative_profile_template.schema.json b/specs/signed_docs/docs/payload_schemas/representative_profile_template.schema.json new file mode 100644 index 0000000000..b2747149a6 --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/representative_profile_template.schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/drep_profile_template.schema.json", + "title": "Representative Profile Template Payload Schema", + "description": "Schema for a Representative profile document template, extending the base profile with Representative-specific fields as defined by the Admin.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + }, + "type": "object", + "additionalProperties": false, + "properties": { + "name": { "type": "string" }, + "bio": { "type": "string" }, + "avatar": { "$ref": "common_definitions.schema.json#/definitions/ipfsUrl" }, + "website": { "$ref": "common_definitions.schema.json#/definitions/url" }, + "social_links": { + "type": "array", + "items": { "$ref": "common_definitions.schema.json#/definitions/url" } + }, + "tags": { + "type": "array", + "items": { "type": "string" } + }, + "avatar_required": { "type": "string", "enum": ["yes", "optional", "excluded"] } + }, + "required": [ + "name", + "bio", + "avatar", + "website", + "social_links", + "tags", + "avatar_required" + ] +} \ No newline at end of file diff --git a/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json b/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json new file mode 100644 index 0000000000..9d2f2b9a7a --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/voter_representative_delegation.schema.json", + "title": "Voter Representative Delegation Payload Schema", + "description": "This payload is submitted when a voter delegates to a Representative, with the voter as the signer and the Representative’s category profile as the referenced document; to revoke the delegation, the voter can publish again with the status set to revoked.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "x-changelog": { + "2025-06-19": [ + "First Version Created." + ] + }, + "type": "object", + "additionalProperties": false, + "properties": { + "status": { + "type": "string", + "enum": ["active", "revoked"], + "description": "The status of the delegation. 'active' signifies delegation (set by default), 'revoked' signifies withdrawal of delegation." + } + }, + "required": ["status"] +} \ No newline at end of file diff --git a/specs/signed_docs/docs/profile.cue b/specs/signed_docs/docs/profile.cue new file mode 100644 index 0000000000..f1086bc7e5 --- /dev/null +++ b/specs/signed_docs/docs/profile.cue @@ -0,0 +1,52 @@ +package signed_docs + +docs: #DocumentDefinitions & { + "Profile": { + description: """ + ## Profile Document + + A profile document for a Catalyst user containing basic user information. + """ + validation: """ + The profile must include both a name and a bio. No additional validation beyond schema and required fields. + """ + business_logic: { + front_end: """ + Display and allow editing of profile fields for the user. + """ + back_end: """ + Validate profile data and store in the system. + """ + } + metadata: { + template: { + required: "yes" + type: "Profile Template" + } + } + payload: { + description: """ + The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template. + """ + } + 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/signed_docs/docs/profile_template.cue b/specs/signed_docs/docs/profile_template.cue new file mode 100644 index 0000000000..e4f33bef5e --- /dev/null +++ b/specs/signed_docs/docs/profile_template.cue @@ -0,0 +1,41 @@ +@extern(embed) + +package signed_docs + +docs: #DocumentDefinitions & { + "Profile Template": { + description: """ + ## Profile Template Document + + Defines the allowed payload contents and constraints for a generic user profile. + """ + metadata: { + // Add any template-specific metadata here if needed + } + payload: { + description: """ + JSON Schema document which defines the valid contents of a profile document. + """ + schema: _ @embed(file="payload_schemas/profile_template.schema.json") + } + signers: { + roles: { + admin: [ + "Brand Admin", + ] + } + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} diff --git a/specs/signed_docs/docs/representative_category_profile.cue b/specs/signed_docs/docs/representative_category_profile.cue new file mode 100644 index 0000000000..290bfac323 --- /dev/null +++ b/specs/signed_docs/docs/representative_category_profile.cue @@ -0,0 +1,73 @@ +package signed_docs + +docs: #DocumentDefinitions & { + "Representative Category Profile": { + description: """ + ## Representative Category Profile Document + + A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. + The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. + + The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. + + The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation. + """ + 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 'Category Parameters' document. + - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document. + - The payload MUST be valid against the JSON schema defined in the referenced template. + """ + business_logic: { + front_end: """ + - Allows a Representative to create or update their profile for a category. + - The status is set to 'active' when created and the Representative is then discoverable for delegation. + - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category. + """ + back_end: """ + - The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. + - The system will only consider Representatives with an 'active' status as eligible for delegation. + """ + } + metadata: { + ref: { + required: "yes" + type: "Representative Profile" + } + parameters: { + required: "yes" + type: "Category Parameters" + } + template: { + required: "yes" + type: "Representative Category Profile Template" + } + } + payload: { + description: """ + The Representative's profile data for a specific category. Its structure is defined by the referenced template document. + It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. + """ + } + signers: { + roles: { + user: [ + "Representative", + ] + } + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} diff --git a/specs/signed_docs/docs/representative_category_profile_template.cue b/specs/signed_docs/docs/representative_category_profile_template.cue new file mode 100644 index 0000000000..0b7f78a628 --- /dev/null +++ b/specs/signed_docs/docs/representative_category_profile_template.cue @@ -0,0 +1,46 @@ +@extern(embed) + +package signed_docs + +docs: #DocumentDefinitions & { + "Representative Category Profile Template": { + description: """ + ## Representative Category Profile Template Document + + Defines the allowed payload contents and constraints for a Representative's category-specific profile. + This template is created by an Admin to enforce a consistent structure for all Representatives within a given category. + """ + headers: { + "content type": { + value: "application/schema+json" + } + } + payload: { + description: """ + JSON Schema document which defines the valid contents of a Representative Category Profile document. + The schema MUST include a 'status' field to indicate if the Representative is active or withdrawn from the category. + """ + schema: _ @embed(file="payload_schemas/representative_category_profile_template.schema.json") + } + signers: { + roles: { + admin: [ + "Brand Admin", + "Campaign Admin", + ] + } + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} diff --git a/specs/signed_docs/docs/representative_profile.cue b/specs/signed_docs/docs/representative_profile.cue new file mode 100644 index 0000000000..86a36c2350 --- /dev/null +++ b/specs/signed_docs/docs/representative_profile.cue @@ -0,0 +1,58 @@ +@extern(embed) + +package signed_docs + +docs: #DocumentDefinitions & { + "Representative Profile": { + description: """ + ## Representative Profile Document + + A Representative-specific profile, extending the minimal profile with Representative-specific fields. + """ + validation: """ + - The signer MUST be a registered 'Representative'. + - The payload MUST be valid against the JSON schema defined in the referenced 'Representative 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 identity across all funds and categories. + """ + back_end: """ + - Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system. + - This global profile is the foundational document referenced by all of the Representative's category-specific profiles. + """ + } + metadata: { + template: { + required: "yes" + type: "Representative Profile Template" + } + } + payload: { + description: """ + The Representative profile payload contains all base profile fields and Representative-specific fields. + Its structure is defined by the referenced Representative Profile Template. + """ + } + signers: { + roles: { + user: [ + "Representative", + ] + } + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} diff --git a/specs/signed_docs/docs/representative_profile_template.cue b/specs/signed_docs/docs/representative_profile_template.cue new file mode 100644 index 0000000000..80488b56a4 --- /dev/null +++ b/specs/signed_docs/docs/representative_profile_template.cue @@ -0,0 +1,34 @@ +@extern(embed) + +package signed_docs + +docs: #DocumentDefinitions & { + "Representative Profile Template": { + description: """ + ## Representative Profile Template Document + + Defines the allowed payload contents and constraints for a Representative profile. + """ + metadata: { + // Add any template-specific metadata here if needed + } + payload: { + description: """ + JSON Schema document which defines the valid contents of a Representative profile document. + """ + schema: _ @embed(file="payload_schemas/representative_profile_template.schema.json") + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} diff --git a/specs/signed_docs/docs/voter_representative_delegation.cue b/specs/signed_docs/docs/voter_representative_delegation.cue new file mode 100644 index 0000000000..f2369ab488 --- /dev/null +++ b/specs/signed_docs/docs/voter_representative_delegation.cue @@ -0,0 +1,64 @@ +@extern(embed) + +package signed_docs + +docs: #DocumentDefinitions & { + "Voter Representative Delegation": { + description: """ + ## Voter Representative Delegation Document + + Captures that a voter (the signer) has delegated to a Representative for a specific category. + The document this refers to (`ref`) is the Representative's Category Profile. + The category itself is specified in the `parameters` metadata. + """ + validation: """ + The payload must contain a 'status' field, which must be either 'active' or 'revoked'. + The Category id for the Representative's Category Profile and as specified in the metadata must match. + """ + business_logic: { + front_end: """ + Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked'). + """ + back_end: """ + Validate the delegation action and update the voter's delegation state for the given category and Representative. + """ + } + metadata: { + ref: { + required: "yes" + type: "Representative Category Profile" + } + parameters: { + required: "yes" + type: "Category Parameters" + } + } + payload: { + description: """ + A minimal payload indicating the intended status of the delegation. + 'active' creates or affirms the delegation. + 'revoked' withdraws the delegation. + """ + schema: _ @embed(file="payload_schemas/voter_representative_delegation.schema.json") + } + signers: { + roles: { + user: [ + "Registered", + ] + } + } + authors: { + "Neil McAuliffe": "neil.mcauliffe@iohk.io" + } + versions: [ + { + version: "0.01" + modified: "2025-06-19" + changes: """ + * First Published Version + """ + }, + ] + } +} From 2c4e2e79e4638c77cd6680807bc610bccd594607 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 19 Jun 2025 18:17:16 +0100 Subject: [PATCH 5/6] docs(docs): Fixed content lenght for md files --- .../08_concepts/signed_doc/docs/profile.md | 18 +++++-- .../signed_doc/docs/profile_template.md | 17 ++---- .../docs/representative_category_profile.md | 38 ++++++------- ...epresentative_category_profile_template.md | 23 +++----- .../signed_doc/docs/representative_profile.md | 12 ++--- .../docs/representative_profile_template.md | 22 +++----- .../docs/voter_representative_delegation.md | 19 +++---- specs/signed_doc.json | 53 ++++++++++++------- specs/signed_docs/docs/profile.cue | 17 ++++-- specs/signed_docs/docs/profile_template.cue | 12 +++++ .../docs/representative_category_profile.cue | 37 ++++++------- ...presentative_category_profile_template.cue | 20 +++++-- .../docs/representative_profile.cue | 12 ++--- .../docs/representative_profile_template.cue | 16 ++++-- .../docs/voter_representative_delegation.cue | 19 +++---- 15 files changed, 184 insertions(+), 151 deletions(-) diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md index af53961018..19ce64f9f5 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/profile.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md @@ -4,7 +4,9 @@ ## Profile Document -A profile document for a Catalyst user containing basic user information. +A minimal user profile that provides basic information about a user. +Its structure is defined by the referenced Profile Template. +It is used as a base for more specific profiles like the Representative Profile. @@ -16,17 +18,21 @@ A profile document for a Catalyst user containing basic user information. ### Validation -The profile must include both a name and a bio. No additional validation beyond schema and required fields. +* The signer must be a registered 'User'. +* The payload must be valid against the [JSON schema] defined in the referenced 'Profile Template'. ### Business Logic #### Front End -Display and allow editing of profile fields for the user. +* Display the user's profile information. +* Allow a user to edit their own profile data. #### Back End -Validate profile data and store in the system. +* Validate and store profile data against the referenced 'Profile_Template'. +* This profile serves as the base document for a user. + Its scope can be extended to create more specific profiles. ## [COSE Header Parameters][RFC9052-HeaderParameters] @@ -100,7 +106,8 @@ The document payload is not valid if it does not validate completely against the ## Payload -The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template. +The profile payload contains all base profile fields. +Its structure is defined by the referenced Profile Template. ## Signers @@ -130,5 +137,6 @@ New versions of this document may be published by: * First Published Version [RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 [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/profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md index 522cf66cf9..b23af06e27 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/profile_template.md @@ -16,26 +16,19 @@ Defines the allowed payload contents and constraints for a generic user profile. ### 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 signer MUST be a registered 'Admin'. +* The payload MUST be a valid [JSON schema]. +* The schema SHOULD define a minimal set of profile fields (e.g., name, bio). ### 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. +* Validate and store the [JSON schema] that defines the structure for all 'Profile' documents. ## [COSE Header Parameters][RFC9052-HeaderParameters] diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md index 536c4588ed..0c47bf8615 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md @@ -2,14 +2,14 @@ ## Description - ## Representative Category Profile Document +## Representative Category Profile Document - A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. - The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. +A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. +The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. - The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. +The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. - The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation. +The payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation. @@ -21,24 +21,25 @@ ### 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 'Category Parameters' document. - - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document. - - The payload MUST be valid against the [JSON schema] defined in the referenced template. + * 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 'Category Parameters' document. + * The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. + * The payload MUST be valid against the [JSON schema] defined in the referenced template. ### Business Logic #### Front End - - Allows a Representative to create or update their profile for a category. - - The status is set to 'active' when created and the Representative is then discoverable for delegation. - - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category. + * 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 can set their status to 'revoked' to signal they are no longer participating in the category, + without having to revoke the document. #### Back End - - The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. - - The system will only consider Representatives with an 'active' status as eligible for delegation. + * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. + * The system will only consider Representatives with an 'active' status as eligible for delegation. ## [COSE Header Parameters][RFC9052-HeaderParameters] @@ -112,7 +113,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. @@ -171,8 +172,9 @@ In addition to the validation performed for [Document Reference](../metadata.md# ## Payload -The Representative's profile data for a specific category. Its structure is defined by the referenced template document. - It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. +The Representative's profile data for a specific category. + Its structure is defined by the referenced template document. + It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. ## Signers diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md index 844ad154e6..6e1140382f 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md @@ -2,10 +2,10 @@ ## Description - ## Representative Category Profile Template Document +## Representative Category Profile Template - Defines the allowed payload contents and constraints for a Representative's category-specific profile. - This template is created by an Admin to enforce a consistent structure for all Representatives within a given category. +Defines the [JSON schema] for a 'Representative Category Profile'. +This allows an 'Admin' to specify different profile requirements for each category. @@ -17,26 +17,19 @@ ### 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 signer MUST be a registered 'Admin'. +* The payload MUST be a valid [JSON schema]. +* The schema MUST include a 'status' field. ### 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. +* Validate and store the [JSON schema] that defines the structure for 'Representative Category Profile' documents. ## [COSE Header Parameters][RFC9052-HeaderParameters] diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md index 1d42d1e926..aaaf8c9434 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile.md @@ -16,20 +16,20 @@ A Representative-specific profile, extending the minimal profile with Representa ### Validation - - The signer MUST be a registered 'Representative'. - - The payload MUST be valid against the [JSON schema] defined in the referenced 'Representative Profile Template'. + * The signer MUST be a registered 'Representative'. + * The payload MUST be valid against the [JSON schema] defined in the referenced 'Representative 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 identity across all funds and categories. +* Display and allow editing of the Representative's core profile fields. +* This profile serves as the central hub for a Representative's identity. #### Back End -- Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system. -- This global profile is the foundational document referenced by all of the Representative's category-specific profiles. +* Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it. +* This global profile is the foundational document referenced by all of the Representative's category-specific profiles. ## [COSE Header Parameters][RFC9052-HeaderParameters] diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md index 1bf64e4a91..5fe7452bec 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md @@ -2,9 +2,10 @@ ## Description - ## Representative Profile Template Document +## Representative Profile Template - Defines the allowed payload contents and constraints for a Representative profile. +Defines the [JSON schema] for a 'Representative Profile'. +This template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles. @@ -16,26 +17,19 @@ ### 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 signer MUST be a registered 'Admin'. +* The payload MUST be a valid [JSON schema]. ### 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. +* Validate and store the [JSON schema] that defines the structure for all 'Representative Profile' documents. +* The schema MUST extend the base 'Profile' schema with Representative-specific fields. ## [COSE Header Parameters][RFC9052-HeaderParameters] diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md index 937d61ed05..d173a35581 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md @@ -2,11 +2,9 @@ ## Description - ## Voter Representative Delegation Document +## Voter Representative Delegation - Captures that a voter (the signer) has delegated to a Representative for a specific category. - The document this refers to (`ref`) is the Representative's Category Profile. - The category itself is specified in the [`parameters`](../metadata.md#parameters) metadata. +A signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category. @@ -18,18 +16,21 @@ ### Validation - The payload must contain a 'status' field, which must be either 'active' or 'revoked'. - The Category id for the Representative's Category Profile and as specified in the metadata must match. +* The signer MUST be a registered 'Voter'. +* The 'ref' metadata field MUST point to a valid 'Representative Category Profile'. +* The payload MUST be empty. ### Business Logic #### Front End - Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked'). +* 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 - Validate the delegation action and update the voter's delegation state for the given category and Representative. +* 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] @@ -103,7 +104,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. diff --git a/specs/signed_doc.json b/specs/signed_doc.json index aff8ba9e5e..a4b8a9e0a6 100644 --- a/specs/signed_doc.json +++ b/specs/signed_doc.json @@ -939,10 +939,10 @@ "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, "business_logic": { - "back_end": "Validate profile data and store in the system.", - "front_end": "Display and allow editing of profile fields for the user." + "back_end": "* Validate and store profile data against the referenced 'Profile_Template'.\n* This profile serves as the base document for a user.\n Its scope can be extended to create more specific profiles.", + "front_end": "* Display the user's profile information.\n* Allow a user to edit their own profile data." }, - "description": "## Profile Document\n\nA profile document for a Catalyst user containing basic user information.", + "description": "## Profile Document\n\nA minimal user profile that provides basic information about a user.\nIts structure is defined by the referenced Profile Template.\nIt is used as a base for more specific profiles like the Representative Profile.", "headers": { "content type": { "coseLabel": 3, @@ -1038,7 +1038,7 @@ }, "notes": [], "payload": { - "description": "The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template." + "description": "The profile payload contains all base profile fields.\nIts structure is defined by the referenced Profile Template." }, "signers": { "roles": { @@ -1053,7 +1053,7 @@ "type": [ "1b70f611-518d-479e-be73-11b5e9cb68a5" ], - "validation": "The profile must include both a name and a bio. No additional validation beyond schema and required fields.", + "validation": "* The signer must be a registered 'User'.\n* The payload must be valid against the JSON schema defined in the referenced 'Profile Template'.", "versions": [ { "changes": "\t* First Published Version", @@ -1066,6 +1066,10 @@ "authors": { "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, + "business_logic": { + "back_end": "* Validate and store the JSON schema that defines the structure for all 'Profile' documents.", + "front_end": "" + }, "description": "## Profile Template Document\n\nDefines the allowed payload contents and constraints for a generic user profile.", "headers": { "content type": { @@ -1209,6 +1213,7 @@ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", "1b70f611-518d-479e-be73-11b5e9cb68a5" ], + "validation": "* The signer MUST be a registered 'Admin'.\n* The payload MUST be a valid JSON schema.\n* The schema SHOULD define a minimal set of profile fields (e.g., name, bio).", "versions": [ { "changes": "\t* First Published Version", @@ -2384,10 +2389,10 @@ "Neil McAuliffe": "neil.mcauliffe@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 with an 'active' status as eligible for delegation.", - "front_end": " - Allows a Representative to create or update their profile for a category.\n - The status is set to 'active' when created and the Representative is then discoverable for delegation.\n - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category." + "back_end": "\t* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.\n\t* The system will only consider Representatives with an 'active' status as eligible for delegation.", + "front_end": "\t* Allows a Representative to create or update their profile for a category.\n\t* The Representative sets their status to 'active' to be discoverable for delegation.\n\t* The Representative can set their status to 'revoked' to signal they are no longer participating in the category,\n\t without having to revoke the document." }, - "description": " ## Representative Category Profile Document\n\n A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\n The presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n \n The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n \n The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation.", + "description": "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation.", "headers": { "content type": { "coseLabel": 3, @@ -2489,7 +2494,7 @@ }, "notes": [], "payload": { - "description": " The Representative's profile data for a specific category. Its structure is defined by the referenced template document.\n It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation." + "description": "\tThe Representative's profile data for a specific category.\n\tIts structure is defined by the referenced template document.\n\tIt MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation." }, "signers": { "roles": { @@ -2504,7 +2509,7 @@ "type": [ "f1a2b3c4-1111-4abc-8def-2345678901aa" ], - "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 'Category Parameters' document.\n - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document.\n - The payload MUST be valid against the JSON schema defined in the referenced template.", + "validation": "\t* The signer MUST be a registered 'Representative'.\n\t* The 'ref' metadata field MUST point to a valid 'Representative Profile' document.\n\t* The 'parameters' metadata field MUST point to a valid 'Category Parameters' document.\n\t* The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document.\n\t* The payload MUST be valid against the JSON schema defined in the referenced template.", "versions": [ { "changes": "* First Published Version", @@ -2517,7 +2522,11 @@ "authors": { "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, - "description": " ## Representative Category Profile Template Document\n\n Defines the allowed payload contents and constraints for a Representative's category-specific profile.\n This template is created by an Admin to enforce a consistent structure for all Representatives within a given category.", + "business_logic": { + "back_end": "* Validate and store the JSON schema that defines the structure for 'Representative Category Profile' documents.", + "front_end": "" + }, + "description": "## Representative Category Profile Template\n\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category.", "headers": { "content type": { "coseLabel": 3, @@ -2667,6 +2676,7 @@ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", "f1a2b3c4-1111-4abc-8def-2345678901aa" ], + "validation": "* The signer MUST be a registered 'Admin'.\n* The payload MUST be a valid JSON schema.\n* The schema MUST include a 'status' field.", "versions": [ { "changes": " * First Published Version", @@ -2680,8 +2690,8 @@ "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, "business_logic": { - "back_end": "- Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system.\n- This global profile is the foundational document referenced by all of the Representative's category-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 identity across all funds and categories." + "back_end": "* Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it.\n* This global profile is the foundational document referenced by all of the Representative's category-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 identity." }, "description": "## Representative Profile Document\n\nA Representative-specific profile, extending the minimal profile with Representative-specific fields.", "headers": { @@ -2794,7 +2804,7 @@ "type": [ "e3f2c1b4-7890-4abc-8def-2345678901ef" ], - "validation": " - The signer MUST be a registered 'Representative'.\n - The payload MUST be valid against the JSON schema defined in the referenced 'Representative Profile Template'.", + "validation": " * The signer MUST be a registered 'Representative'.\n * The payload MUST be valid against the JSON schema defined in the referenced 'Representative Profile Template'.", "versions": [ { "changes": "* First Published Version", @@ -2807,7 +2817,11 @@ "authors": { "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, - "description": " ## Representative Profile Template Document\n\n Defines the allowed payload contents and constraints for a Representative profile.", + "business_logic": { + "back_end": "* Validate and store the JSON schema that defines the structure for all 'Representative Profile' documents.\n* The schema MUST extend the base 'Profile' schema with Representative-specific fields.", + "front_end": "" + }, + "description": "## Representative Profile Template\n\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles.", "headers": { "content type": { "coseLabel": 3, @@ -2978,6 +2992,7 @@ "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", "e3f2c1b4-7890-4abc-8def-2345678901ef" ], + "validation": "* The signer MUST be a registered 'Admin'.\n* The payload MUST be a valid JSON schema.", "versions": [ { "changes": " * First Published Version", @@ -2991,10 +3006,10 @@ "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, "business_logic": { - "back_end": " Validate the delegation action and update the voter's delegation state for the given category and Representative.", - "front_end": " Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked')." + "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": " ## Voter Representative Delegation Document\n\n Captures that a voter (the signer) has delegated to a Representative for a specific category.\n The document this refers to (`ref`) is the Representative's Category Profile.\n The category itself is specified in the `parameters` metadata.", + "description": "## Voter Representative Delegation\n\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category.", "headers": { "content type": { "coseLabel": 3, @@ -3140,7 +3155,7 @@ "type": [ "f1a2b3c4-3333-4abc-8def-2345678901cc" ], - "validation": " The payload must contain a 'status' field, which must be either 'active' or 'revoked'.\n The Category id for the Representative's Category Profile and as specified in the metadata must match. ", + "validation": "* The signer MUST be a registered 'Voter'.\n* The 'ref' metadata field MUST point to a valid 'Representative Category Profile'.\n* The payload MUST be empty.", "versions": [ { "changes": "* First Published Version", diff --git a/specs/signed_docs/docs/profile.cue b/specs/signed_docs/docs/profile.cue index f1086bc7e5..739aed10f6 100644 --- a/specs/signed_docs/docs/profile.cue +++ b/specs/signed_docs/docs/profile.cue @@ -5,17 +5,23 @@ docs: #DocumentDefinitions & { description: """ ## Profile Document - A profile document for a Catalyst user containing basic user information. + A minimal user profile that provides basic information about a user. + Its structure is defined by the referenced Profile Template. + It is used as a base for more specific profiles like the Representative Profile. """ validation: """ - The profile must include both a name and a bio. No additional validation beyond schema and required fields. + * The signer must be a registered 'User'. + * The payload must be valid against the JSON schema defined in the referenced 'Profile Template'. """ business_logic: { front_end: """ - Display and allow editing of profile fields for the user. + * Display the user's profile information. + * Allow a user to edit their own profile data. """ back_end: """ - Validate profile data and store in the system. + * Validate and store profile data against the referenced 'Profile_Template'. + * This profile serves as the base document for a user. + Its scope can be extended to create more specific profiles. """ } metadata: { @@ -26,7 +32,8 @@ docs: #DocumentDefinitions & { } payload: { description: """ - The profile payload contains the minimum profile information for a user. Its structure is defined by the referenced Profile Template. + The profile payload contains all base profile fields. + Its structure is defined by the referenced Profile Template. """ } signers: { diff --git a/specs/signed_docs/docs/profile_template.cue b/specs/signed_docs/docs/profile_template.cue index e4f33bef5e..2fece1a71c 100644 --- a/specs/signed_docs/docs/profile_template.cue +++ b/specs/signed_docs/docs/profile_template.cue @@ -9,6 +9,18 @@ docs: #DocumentDefinitions & { Defines the allowed payload contents and constraints for a generic user profile. """ + validation: """ + * The signer MUST be a registered 'Admin'. + * The payload MUST be a valid JSON schema. + * The schema SHOULD define a minimal set of profile fields (e.g., name, bio). + """ + business_logic: { + front_end: """ + """ + back_end: """ + * Validate and store the JSON schema that defines the structure for all 'Profile' documents. + """ + } metadata: { // Add any template-specific metadata here if needed } diff --git a/specs/signed_docs/docs/representative_category_profile.cue b/specs/signed_docs/docs/representative_category_profile.cue index 290bfac323..25bec52bd8 100644 --- a/specs/signed_docs/docs/representative_category_profile.cue +++ b/specs/signed_docs/docs/representative_category_profile.cue @@ -2,32 +2,24 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Category Profile": { - description: """ - ## Representative Category Profile Document - - A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. - The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. - - The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. - - The payload must include a status field, indicating whether the Representative is currently active or has revoked their participation. - """ + description: "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation." 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 'Category Parameters' document. - - The 'template' metadata field MUST point to a valid 'Representative_Category_Profile_Template' document. - - The payload MUST be valid against the JSON schema defined in the referenced template. + * 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 'Category Parameters' document. + * The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. + * The payload MUST be valid against the JSON schema defined in the referenced template. """ business_logic: { front_end: """ - - Allows a Representative to create or update their profile for a category. - - The status is set to 'active' when created and the Representative is then discoverable for delegation. - - The Representative can opt-out and their status set to 'revoked' to signal they are no longer participating in the category. + * 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 can set their status to 'revoked' to signal they are no longer participating in the category, + without having to revoke the document. """ back_end: """ - - The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. - - The system will only consider Representatives with an 'active' status as eligible for delegation. + * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. + * The system will only consider Representatives with an 'active' status as eligible for delegation. """ } metadata: { @@ -46,8 +38,9 @@ docs: #DocumentDefinitions & { } payload: { description: """ - The Representative's profile data for a specific category. Its structure is defined by the referenced template document. - It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. + The Representative's profile data for a specific category. + Its structure is defined by the referenced template document. + It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. """ } signers: { diff --git a/specs/signed_docs/docs/representative_category_profile_template.cue b/specs/signed_docs/docs/representative_category_profile_template.cue index 0b7f78a628..344d8d1bd0 100644 --- a/specs/signed_docs/docs/representative_category_profile_template.cue +++ b/specs/signed_docs/docs/representative_category_profile_template.cue @@ -4,12 +4,22 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Category Profile Template": { - description: """ - ## Representative Category Profile Template Document - - Defines the allowed payload contents and constraints for a Representative's category-specific profile. - This template is created by an Admin to enforce a consistent structure for all Representatives within a given category. + description: "## Representative Category Profile Template\n\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category." + validation: """ + * The signer MUST be a registered 'Admin'. + * The payload MUST be a valid JSON schema. + * The schema MUST include a 'status' field. """ + business_logic: { + front_end: """ + """ + back_end: """ + * Validate and store the JSON schema that defines the structure for 'Representative Category Profile' documents. + """ + } + metadata: { + // Add any template-specific metadata here if needed + } headers: { "content type": { value: "application/schema+json" diff --git a/specs/signed_docs/docs/representative_profile.cue b/specs/signed_docs/docs/representative_profile.cue index 86a36c2350..3ba9658e3c 100644 --- a/specs/signed_docs/docs/representative_profile.cue +++ b/specs/signed_docs/docs/representative_profile.cue @@ -10,17 +10,17 @@ docs: #DocumentDefinitions & { A Representative-specific profile, extending the minimal profile with Representative-specific fields. """ validation: """ - - The signer MUST be a registered 'Representative'. - - The payload MUST be valid against the JSON schema defined in the referenced 'Representative Profile Template'. + * The signer MUST be a registered 'Representative'. + * The payload MUST be valid against the JSON schema defined in the referenced 'Representative 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 identity across all funds and categories. + * Display and allow editing of the Representative's core profile fields. + * This profile serves as the central hub for a Representative's identity. """ back_end: """ - - Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it in the system. - - This global profile is the foundational document referenced by all of the Representative's category-specific profiles. + * Validate Representative profile data against the referenced 'Representative_Profile_Template' and store it. + * This global profile is the foundational document referenced by all of the Representative's category-specific profiles. """ } metadata: { diff --git a/specs/signed_docs/docs/representative_profile_template.cue b/specs/signed_docs/docs/representative_profile_template.cue index 80488b56a4..8937f19ea7 100644 --- a/specs/signed_docs/docs/representative_profile_template.cue +++ b/specs/signed_docs/docs/representative_profile_template.cue @@ -4,11 +4,19 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Profile Template": { - description: """ - ## Representative Profile Template Document - - Defines the allowed payload contents and constraints for a Representative profile. + description: "## Representative Profile Template\n\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles." + validation: """ + * The signer MUST be a registered 'Admin'. + * The payload MUST be a valid JSON schema. """ + business_logic: { + front_end: """ + """ + back_end: """ + * Validate and store the JSON schema that defines the structure for all 'Representative Profile' documents. + * The schema MUST extend the base 'Profile' schema with Representative-specific fields. + """ + } metadata: { // Add any template-specific metadata here if needed } diff --git a/specs/signed_docs/docs/voter_representative_delegation.cue b/specs/signed_docs/docs/voter_representative_delegation.cue index f2369ab488..6920f50087 100644 --- a/specs/signed_docs/docs/voter_representative_delegation.cue +++ b/specs/signed_docs/docs/voter_representative_delegation.cue @@ -4,23 +4,20 @@ package signed_docs docs: #DocumentDefinitions & { "Voter Representative Delegation": { - description: """ - ## Voter Representative Delegation Document - - Captures that a voter (the signer) has delegated to a Representative for a specific category. - The document this refers to (`ref`) is the Representative's Category Profile. - The category itself is specified in the `parameters` metadata. - """ + description: "## Voter Representative Delegation\n\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category." validation: """ - The payload must contain a 'status' field, which must be either 'active' or 'revoked'. - The Category id for the Representative's Category Profile and as specified in the metadata must match. + * The signer MUST be a registered 'Voter'. + * The 'ref' metadata field MUST point to a valid 'Representative Category Profile'. + * The payload MUST be empty. """ business_logic: { front_end: """ - Allow voters to delegate to a Representative for a category ('active') or revoke that delegation ('revoked'). + * 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: """ - Validate the delegation action and update the voter's delegation state for the given category and Representative. + * 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. """ } metadata: { From 3f5c4e801da62fa2bd4f974ae7854fbc56ee285e Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 19 Jun 2025 20:30:59 +0100 Subject: [PATCH 6/6] docs(docs): Fixed content lenght and formating --- .../08_concepts/signed_doc/docs/profile.md | 2 +- .../docs/representative_category_profile.md | 29 +++++++++---------- ...epresentative_category_profile_template.md | 1 - .../docs/representative_profile_template.md | 1 - .../docs/voter_representative_delegation.md | 3 +- specs/signed_doc.json | 18 ++++++------ specs/signed_docs/docs/profile.cue | 2 +- .../docs/representative_category_profile.cue | 29 +++++++++---------- ...presentative_category_profile_template.cue | 2 +- .../docs/representative_profile_template.cue | 2 +- .../docs/voter_representative_delegation.cue | 2 +- 11 files changed, 43 insertions(+), 48 deletions(-) diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md index 19ce64f9f5..3ccd3d0273 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/profile.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/profile.md @@ -134,7 +134,7 @@ New versions of this document may be published by: #### 0.01 (2025-06-19) - * First Published Version +* First Published Version [RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 [JSON Schema]: https://json-schema.org/draft-07 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md index 0c47bf8615..f6c354e38d 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile.md @@ -5,7 +5,7 @@ ## Representative Category Profile Document A Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative. -The presence of this docuemnt signifies the user's intent to participate in that category as a Representative. +The presence of this document signifies the user's intent to participate in that category as a Representative. The document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements. @@ -21,25 +21,24 @@ The payload must contain a 'status' field to indicate if the Representative is a ### 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 'Category Parameters' document. - * The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. - * The payload MUST be valid against the [JSON schema] defined in the referenced template. +* 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 'Category Parameters' document. +* The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. +* The payload MUST be valid against the [JSON schema] defined in the referenced template. ### 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 can set their status to 'revoked' to signal they are no longer participating in the category, - without having to revoke the document. +* 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 can set their status to 'revoked' to signal they are no longer participating in the category, without having to revoke the document. #### Back End - * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. - * The system will only consider Representatives with an 'active' status as eligible for delegation. +* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. +* The system will only consider Representatives with an 'active' status as eligible for delegation. ## [COSE Header Parameters][RFC9052-HeaderParameters] @@ -113,7 +112,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. @@ -173,8 +172,8 @@ In addition to the validation performed for [Document Reference](../metadata.md# ## Payload The Representative's profile data for a specific category. - Its structure is defined by the referenced template document. - It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. +Its structure is defined by the referenced template document. +It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. ## Signers diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md index 6e1140382f..13ab60679c 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_category_profile_template.md @@ -3,7 +3,6 @@ ## Description ## Representative Category Profile Template - Defines the [JSON schema] for a 'Representative Category Profile'. This allows an 'Admin' to specify different profile requirements for each category. diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md index 5fe7452bec..b1d3a64a23 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/representative_profile_template.md @@ -3,7 +3,6 @@ ## Description ## Representative Profile Template - Defines the [JSON schema] for a 'Representative Profile'. This template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles. diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md index d173a35581..168e8a839e 100644 --- a/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md +++ b/docs/src/architecture/08_concepts/signed_doc/docs/voter_representative_delegation.md @@ -3,7 +3,6 @@ ## Description ## Voter Representative Delegation - A signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category. @@ -104,7 +103,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. diff --git a/specs/signed_doc.json b/specs/signed_doc.json index a4b8a9e0a6..8c59764853 100644 --- a/specs/signed_doc.json +++ b/specs/signed_doc.json @@ -1056,7 +1056,7 @@ "validation": "* The signer must be a registered 'User'.\n* The payload must be valid against the JSON schema defined in the referenced 'Profile Template'.", "versions": [ { - "changes": "\t* First Published Version", + "changes": "* First Published Version", "modified": "2025-06-19", "version": "0.01" } @@ -2389,10 +2389,10 @@ "Neil McAuliffe": "neil.mcauliffe@iohk.io" }, "business_logic": { - "back_end": "\t* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.\n\t* The system will only consider Representatives with an 'active' status as eligible for delegation.", - "front_end": "\t* Allows a Representative to create or update their profile for a category.\n\t* The Representative sets their status to 'active' to be discoverable for delegation.\n\t* The Representative can set their status to 'revoked' to signal they are no longer participating in the category,\n\t without having to revoke the document." + "back_end": "* The backend MUST verify the signer is a 'Representative' and that all referenced documents exist.\n* The system will only consider Representatives with an 'active' status as eligible for delegation.", + "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 can set their status to 'revoked' to signal they are no longer participating in the category, without having to revoke the document." }, - "description": "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation.", + "description": "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this document signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation.", "headers": { "content type": { "coseLabel": 3, @@ -2494,7 +2494,7 @@ }, "notes": [], "payload": { - "description": "\tThe Representative's profile data for a specific category.\n\tIts structure is defined by the referenced template document.\n\tIt MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation." + "description": "The Representative's profile data for a specific category.\nIts structure is defined by the referenced template document.\nIt MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation." }, "signers": { "roles": { @@ -2509,7 +2509,7 @@ "type": [ "f1a2b3c4-1111-4abc-8def-2345678901aa" ], - "validation": "\t* The signer MUST be a registered 'Representative'.\n\t* The 'ref' metadata field MUST point to a valid 'Representative Profile' document.\n\t* The 'parameters' metadata field MUST point to a valid 'Category Parameters' document.\n\t* The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document.\n\t* The payload MUST be valid against the JSON schema defined in the referenced template.", + "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 'Category Parameters' document.\n* The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document.\n* The payload MUST be valid against the JSON schema defined in the referenced template.", "versions": [ { "changes": "* First Published Version", @@ -2526,7 +2526,7 @@ "back_end": "* Validate and store the JSON schema that defines the structure for 'Representative Category Profile' documents.", "front_end": "" }, - "description": "## Representative Category Profile Template\n\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category.", + "description": "## Representative Category Profile Template\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category.", "headers": { "content type": { "coseLabel": 3, @@ -2821,7 +2821,7 @@ "back_end": "* Validate and store the JSON schema that defines the structure for all 'Representative Profile' documents.\n* The schema MUST extend the base 'Profile' schema with Representative-specific fields.", "front_end": "" }, - "description": "## Representative Profile Template\n\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles.", + "description": "## Representative Profile Template\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles.", "headers": { "content type": { "coseLabel": 3, @@ -3009,7 +3009,7 @@ "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": "## Voter Representative Delegation\n\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category.", + "description": "## Voter Representative Delegation\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category.", "headers": { "content type": { "coseLabel": 3, diff --git a/specs/signed_docs/docs/profile.cue b/specs/signed_docs/docs/profile.cue index 739aed10f6..3b8817cf26 100644 --- a/specs/signed_docs/docs/profile.cue +++ b/specs/signed_docs/docs/profile.cue @@ -51,7 +51,7 @@ docs: #DocumentDefinitions & { version: "0.01" modified: "2025-06-19" changes: """ - * First Published Version + * First Published Version """ }, ] diff --git a/specs/signed_docs/docs/representative_category_profile.cue b/specs/signed_docs/docs/representative_category_profile.cue index 25bec52bd8..bcf848e0bb 100644 --- a/specs/signed_docs/docs/representative_category_profile.cue +++ b/specs/signed_docs/docs/representative_category_profile.cue @@ -2,24 +2,23 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Category Profile": { - description: "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this docuemnt signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation." + description: "## Representative Category Profile Document\n\nA Representative Category Profile is created to opt in as a Representative for a specific campaign category, the user must have registered as a Representative.\nThe presence of this document signifies the user's intent to participate in that category as a Representative.\n\nThe document's structure is defined by the associated Representative_Category_Profile_Template, which allows an Admin to specify category-specific requirements.\n\nThe payload must contain a 'status' field to indicate if the Representative is active or has revoked their participation." 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 'Category Parameters' document. - * The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. - * The payload MUST be valid against the JSON schema defined in the referenced template. + * 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 'Category Parameters' document. + * The 'template' metadata field MUST point to a valid 'Representative Category Profile Template' document. + * The payload MUST be valid against the JSON schema defined in the referenced template. """ 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 can set their status to 'revoked' to signal they are no longer participating in the category, - without having to revoke the document. + * 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 can set their status to 'revoked' to signal they are no longer participating in the category, without having to revoke the document. """ back_end: """ - * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. - * The system will only consider Representatives with an 'active' status as eligible for delegation. + * The backend MUST verify the signer is a 'Representative' and that all referenced documents exist. + * The system will only consider Representatives with an 'active' status as eligible for delegation. """ } metadata: { @@ -38,9 +37,9 @@ docs: #DocumentDefinitions & { } payload: { description: """ - The Representative's profile data for a specific category. - Its structure is defined by the referenced template document. - It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. + The Representative's profile data for a specific category. + Its structure is defined by the referenced template document. + It MUST contain a 'status' field ('active' or 'revoked') to manage the Representative's participation. """ } signers: { diff --git a/specs/signed_docs/docs/representative_category_profile_template.cue b/specs/signed_docs/docs/representative_category_profile_template.cue index 344d8d1bd0..805f3e144a 100644 --- a/specs/signed_docs/docs/representative_category_profile_template.cue +++ b/specs/signed_docs/docs/representative_category_profile_template.cue @@ -4,7 +4,7 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Category Profile Template": { - description: "## Representative Category Profile Template\n\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category." + description: "## Representative Category Profile Template\nDefines the JSON schema for a 'Representative Category Profile'.\nThis allows an 'Admin' to specify different profile requirements for each category." validation: """ * The signer MUST be a registered 'Admin'. * The payload MUST be a valid JSON schema. diff --git a/specs/signed_docs/docs/representative_profile_template.cue b/specs/signed_docs/docs/representative_profile_template.cue index 8937f19ea7..aad79b365a 100644 --- a/specs/signed_docs/docs/representative_profile_template.cue +++ b/specs/signed_docs/docs/representative_profile_template.cue @@ -4,7 +4,7 @@ package signed_docs docs: #DocumentDefinitions & { "Representative Profile Template": { - description: "## Representative Profile Template\n\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles." + description: "## Representative Profile Template\nDefines the JSON schema for a 'Representative Profile'.\nThis template allows an 'Admin' to enforce a specific structure and set of constraints for Representative profiles." validation: """ * The signer MUST be a registered 'Admin'. * The payload MUST be a valid JSON schema. diff --git a/specs/signed_docs/docs/voter_representative_delegation.cue b/specs/signed_docs/docs/voter_representative_delegation.cue index 6920f50087..34617c6b68 100644 --- a/specs/signed_docs/docs/voter_representative_delegation.cue +++ b/specs/signed_docs/docs/voter_representative_delegation.cue @@ -4,7 +4,7 @@ package signed_docs docs: #DocumentDefinitions & { "Voter Representative Delegation": { - description: "## Voter Representative Delegation\n\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category." + description: "## Voter Representative Delegation\nA signed document that allows a 'Voter' to delegate their voting power to a 'Representative' for a specific category." validation: """ * The signer MUST be a registered 'Voter'. * The 'ref' metadata field MUST point to a valid 'Representative Category Profile'.