[rtems-central commit] packagemanual: New

Sebastian Huber sebh at rtems.org
Tue Nov 21 13:35:41 UTC 2023


Module:    rtems-central
Branch:    master
Commit:    cc0ab75a2c65917cee72410c514d9c4a90275f3a
Changeset: http://git.rtems.org/rtems-central/commit/?id=cc0ab75a2c65917cee72410c514d9c4a90275f3a

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Nov 21 11:13:16 2023 +0100

packagemanual: New

---

 rtemsspec/packagebuildfactory.py                   |   7 +
 rtemsspec/packagechanges.py                        | 121 ++++
 rtemsspec/packagemanual.py                         | 463 +++++++++++++++
 rtemsspec/rtems.py                                 |  20 +-
 rtemsspec/sreldbuilder.py                          |  51 ++
 .../tests/spec-packagebuild/qdp/build/disabled.yml |  13 +
 .../spec-packagebuild/qdp/build/doc-ddf-sreld.yml  |  13 +
 .../qdp/build/doc-package-manual.yml               |  13 +
 .../qdp/deployment/doc-ddf-sreld.yml               |  13 +
 .../qdp/deployment/doc-package-manual.yml          |  13 +
 .../spec-packagebuild/qdp/issue/rtems/2189.yml     |  15 +
 .../spec-packagebuild/qdp/issue/rtems/2365.yml     |  15 +
 .../spec-packagebuild/qdp/issue/rtems/2548.yml     |  15 +
 .../spec-packagebuild/qdp/issue/rtems/database.yml |  10 +
 .../tests/spec-packagebuild/qdp/package-build.yml  |   4 +
 .../spec-packagebuild/qdp/package-changes.yml      |  16 +
 .../qdp/package-status/test-1.yml                  |  13 +
 .../qdp/package-status/test-2.yml                  |  16 +
 rtemsspec/tests/spec-packagebuild/qdp/repo/a.yml   |  22 +
 rtemsspec/tests/spec-packagebuild/qdp/repo/b.yml   |  22 +
 rtemsspec/tests/spec-packagebuild/qdp/source/a.yml |   6 +-
 .../tests/spec-packagebuild/qdp/source/archive.yml |  15 +
 .../spec-packagebuild/qdp/source/doc-ddf-sreld.yml |  15 +
 .../qdp/source/doc-package-manual.yml              |  15 +
 .../spec-packagebuild/qdp/steps/archive-2.yml      |  23 +
 .../spec-packagebuild/qdp/steps/doc-ddf-sreld.yml  |  47 ++
 .../qdp/steps/doc-package-manual.yml               |  84 +++
 .../spec-packagebuild/qdp/test-logs/membench-2.yml |  15 +
 .../tests/spec-packagebuild/qdp/test-logs/perf.yml |  15 +
 rtemsspec/tests/spec-packagebuild/req/api.yml      |  14 +
 rtemsspec/tests/spec-packagebuild/rtems/group.yml  |   2 +-
 .../spec-packagebuild/rtems/req/mem-basic.yml      |  15 +
 .../tests/spec-packagebuild/rtems/req/perf.yml     |  25 +
 .../tests/spec-packagebuild/rtems/target-a.yml     |  19 +
 .../tests/spec-packagebuild/rtems/target-b.yml     |  19 +
 .../spec-packagebuild/rtems/val/mem-basic.yml      |  54 ++
 .../pkg/build/src/doc-ddf-sreld/index.rst          |   6 +
 .../pkg/build/src/doc-package-manual/index.rst     |  29 +
 .../tests/test-files/pkg/build/src/membench.json   |  16 +
 rtemsspec/tests/test-files/pkg/test-log-perf.json  | 637 +++++++++++++++++++++
 rtemsspec/tests/test_packagebuild.py               | 452 ++++++++++++++-
 spec-qdp/spec/qdp-doc-ddf-sreld.yml                |  22 +
 spec-qdp/spec/qdp-git-hash.yml                     |  18 +
 spec-qdp/spec/qdp-input-generic-role.yml           |   4 +
 spec-qdp/spec/qdp-issue-database.yml               |  34 ++
 spec-qdp/spec/qdp-issue-member-role.yml            |  23 +
 spec-qdp/spec/qdp-issue-role.yml                   |  27 +
 spec-qdp/spec/qdp-issue-status.yml                 |  20 +
 spec-qdp/spec/qdp-issue.yml                        |  50 ++
 spec-qdp/spec/qdp-optional-git-hash.yml            |  19 +
 spec-qdp/spec/qdp-package-change-list.yml          |  16 +
 spec-qdp/spec/qdp-package-change.yml               |  30 +
 spec-qdp/spec/qdp-package-changes.yml              |  26 +
 spec-qdp/spec/qdp-package-manual.yml               |  30 +
 spec-qdp/spec/qdp-package-status.yml               |  26 +
 55 files changed, 2733 insertions(+), 10 deletions(-)

diff --git a/rtemsspec/packagebuildfactory.py b/rtemsspec/packagebuildfactory.py
index 4e7567e0..febc5964 100644
--- a/rtemsspec/packagebuildfactory.py
+++ b/rtemsspec/packagebuildfactory.py
@@ -29,11 +29,14 @@ from rtemsspec.directorystate import DirectoryState
 from rtemsspec.gcdaproducer import GCDAProducer
 from rtemsspec.membenchcollector import MembenchCollector
 from rtemsspec.packagebuild import BuildItemFactory, PackageVariant
+from rtemsspec.packagechanges import PackageChanges
+from rtemsspec.packagemanual import PackageManualBuilder
 from rtemsspec.reposubset import RepositorySubset
 from rtemsspec.rtems import RTEMSItemCache
 from rtemsspec.runactions import RunActions
 from rtemsspec.runtests import RunTests, TestLog
 from rtemsspec.sphinxbuilder import SphinxBuilder, SphinxSection
+from rtemsspec.sreldbuilder import SRelDBuilder
 from rtemsspec.testrunner import DummyTestRunner, GRMONManualTestRunner, \
     SubprocessTestRunner
 
@@ -50,12 +53,16 @@ def create_build_item_factory() -> BuildItemFactory:
     factory.add_constructor("qdp/build-step/rtems-item-cache", RTEMSItemCache)
     factory.add_constructor("qdp/build-step/run-actions", RunActions)
     factory.add_constructor("qdp/build-step/run-tests", RunTests)
+    factory.add_constructor("qdp/build-step/sphinx/ddf-sreld", SRelDBuilder)
     factory.add_constructor("qdp/build-step/sphinx/generic", SphinxBuilder)
+    factory.add_constructor("qdp/build-step/sphinx/package-manual",
+                            PackageManualBuilder)
     factory.add_constructor("qdp/directory-state/generic", DirectoryState)
     factory.add_constructor("qdp/directory-state/repository", DirectoryState)
     factory.add_constructor("qdp/directory-state/test-log", TestLog)
     factory.add_constructor("qdp/directory-state/unpacked-archive",
                             DirectoryState)
+    factory.add_constructor("qdp/package-changes", PackageChanges)
     factory.add_constructor("qdp/sphinx-section", SphinxSection)
     factory.add_constructor("qdp/test-runner/dummy", DummyTestRunner)
     factory.add_constructor("qdp/test-runner/grmon-manual",
diff --git a/rtemsspec/packagechanges.py b/rtemsspec/packagechanges.py
new file mode 100644
index 00000000..c26668f8
--- /dev/null
+++ b/rtemsspec/packagechanges.py
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: BSD-2-Clause
+""" This module provides support to describe package changes. """
+
+# Copyright (C) 2023 embedded brains GmbH & Co. KG
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import itertools
+from typing import Dict, List, Set, Tuple
+
+from rtemsspec.items import Item, ItemMapper
+from rtemsspec.packagebuild import BuildItem
+from rtemsspec.sphinxcontent import SphinxContent
+
+
+def _issue_prologue(status: str) -> str:
+    return ("When the QDP of this package version was produced, "
+            f"there were the following {status} issues associated:")
+
+
+def _add_issues(content: SphinxContent, issues: Set[Item], header: str,
+                prologue: str, which: str) -> None:
+    with content.section(header):
+        if issues:
+            content.add(prologue)
+            rows: List[Tuple[str,
+                             ...]] = [("Database", "Identifier", "Subject")]
+            for item in sorted(issues):
+                database = item.parent("issue-member")
+                url = ItemMapper(item).substitute(database["url"])
+                identifier = f"`{item['identifier']} <{url}>`_"
+                subject = item["subject"].replace("`", "\\`")
+                rows.append((database["name"], identifier, subject))
+            content.add_grid_table(rows, [27, 14, 59])
+        else:
+            content.add(f"""When the QDP of this package version was produced,
+there were no {which} issues associated.""")
+
+
+class PackageChanges(BuildItem):
+    """ Describes package changes. """
+
+    def _get_issues(self, change: Dict[str,
+                                       str]) -> Tuple[Set[Item], Set[Item]]:
+        issues: Tuple[Set[Item], Set[Item]] = (set(), set())
+        package_status = self.item.map(change["package-status"])
+        for link in package_status.links_to_parents("issue"):
+            issues[int(link["status"] == "open")].add(link.item)
+        return issues
+
+    def _get_change_list(self, section_level: int,
+                         with_description: bool) -> List[SphinxContent]:
+        change_list: List[SphinxContent] = []
+        past_issues: Tuple[Set[Item], Set[Item]] = (set(), set())
+        previous_issues: Tuple[Set[Item], Set[Item]] = (set(), set())
+        for change in self["change-list"]:
+            for past, previous in zip(past_issues, previous_issues):
+                past.update(previous)
+            content = SphinxContent(section_level=section_level)
+            if with_description:
+                content.add_blank_line()
+                content.open_section(change["name"])
+                content.add(change["description"])
+            current_issues = self._get_issues(change)
+            new_issues = current_issues[1].difference(previous_issues[1])
+            _add_issues(content, new_issues, "New issues",
+                        _issue_prologue("new"), "new")
+            open_issues = current_issues[1].intersection(previous_issues[1])
+            _add_issues(content, open_issues, "Open issues",
+                        _issue_prologue("open"), "open")
+            closed_issues = current_issues[0].difference(past_issues[0])
+            _add_issues(
+                content, closed_issues, "Closed issues",
+                "The following issues were closed "
+                "for this package version.", "closed")
+            if with_description:
+                content.close_section()
+            change_list.insert(0, content)
+            previous_issues = current_issues
+        return change_list
+
+    def get_change_list(self, section_level: int) -> str:
+        """ Gets the change list using the section level. """
+        change_list = self._get_change_list(section_level, True)
+        return "\n".join(itertools.chain.from_iterable(change_list))
+
+    def get_open_issues(self, section_level: int) -> str:
+        """ Gets the open issues using the section level. """
+        content = SphinxContent(section_level=section_level)
+        _, open_issues = self._get_issues(self["change-list"][-1])
+        _add_issues(content, open_issues, "Open issues",
+                    _issue_prologue("open"), "open")
+        return "\n".join(content)
+
+    def get_current_changes(self) -> str:
+        """ Gets the current changes. """
+        return self["change-list"][-1]["description"]
+
+    def get_current_issues(self, section_level: int) -> str:
+        """ Gets the current issues using the section level. """
+        change_list = self._get_change_list(section_level, False)
+        return "\n".join(change_list[0])
diff --git a/rtemsspec/packagemanual.py b/rtemsspec/packagemanual.py
new file mode 100644
index 00000000..51bea295
--- /dev/null
+++ b/rtemsspec/packagemanual.py
@@ -0,0 +1,463 @@
+# SPDX-License-Identifier: BSD-2-Clause
+""" This module provides support to build the package manual. """
+
+# Copyright (C) 2020, 2023 embedded brains GmbH & Co. KG
+# Copyright (C) 2021 EDISOFT (https://www.edisoft.pt/)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import json
+import os
+from typing import Any, Dict, List, Optional, Set, Tuple
+
+from rtemsspec.items import Item, ItemGetValueContext
+from rtemsspec.archiver import Archiver
+from rtemsspec.content import BSD_2_CLAUSE_LICENSE, Copyrights
+from rtemsspec.directorystate import DirectoryState
+from rtemsspec.membench import generate, generate_variants_table, \
+    MembenchVariant
+from rtemsspec.packagebuild import PackageBuildDirector
+from rtemsspec.packagechanges import PackageChanges
+from rtemsspec.rtems import gather_api_items
+from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper
+from rtemsspec.sphinxbuilder import SphinxBuilder
+from rtemsspec.util import base64_to_hex, run_command
+
+_Measurements = Dict[str, Dict[str, Tuple[float, float, float]]]
+
+
+def _run_pkg_config(content: SphinxContent, cmd: List[str]) -> None:
+    cmd = ["pkg-config"] + cmd
+    content.add(f"$$ {' '.join(cmd)}")
+    stdout: List[str] = []
+    status = run_command(cmd, stdout=stdout)
+    assert status == 0
+    content.append(stdout)
+
+
+def _format_digest(digest: Optional[str]) -> str:
+    assert digest is not None
+    return "\u200b".join(iter(base64_to_hex(digest)))
+
+
+def _format_line(line: str) -> str:
+    line = line.rstrip("\r\n").replace("\t", "        ")
+    return f"\u200b{line}"
+
+
+def _format_path(path: str) -> str:
+    for char in "/-_.":
+        path = path.replace(char, f"{char}\u200b")
+    return path
+
+
+def _make_code_block(code: List[str]) -> str:
+    content = SphinxContent()
+    for line in range(0, len(code), 100):
+        with content.directive("code-block", value="none"):
+            content.add([_format_line(line) for line in code[line:line + 100]])
+    return "\n".join(content)
+
+
+def _make_targets(targets: str) -> List[str]:
+    if targets:
+        return targets.split(" ")
+    return []
+
+
+def _gather_runtime_performance_items(items: Set[Item], item: Item) -> None:
+    if item.type == "requirement/non-functional/performance-runtime":
+        items.add(item)
+    for child in item.children("requirement-refinement"):
+        _gather_runtime_performance_items(items, child)
+
+
+def _environment_order(name: str) -> int:
+    if name == "HotCache":
+        return 0
+    if name == "FullCache":
+        return 1
+    if name == "DirtyCache":
+        return 2
+    return int(name[5:]) + 2
+
+
+def _add_licenses(content: SphinxContent, deployment_directory: str,
+                  member: DirectoryState, bsd_2_clause: Copyrights) -> None:
+    copyrights_by_license = member["copyrights-by-license"]
+    files = copyrights_by_license.get("files", None)
+    if files is not None:
+        directory = os.path.relpath(member.directory, deployment_directory)
+        with content.section(f"Directory - {directory}"):
+            content.add(copyrights_by_license.get("description", None))
+            for name in files:
+                with content.section(f"File - {name}"):
+                    content.add(f"""The license file
+:file:`{_format_path(os.path.join(directory, name))}`
+is applicable to this directory or parts of the directory:""")
+                    content.add_blank_line()
+                    file_path = os.path.join(member.directory, name)
+                    with open(file_path, "r", encoding="utf-8") as src:
+                        content.add(_make_code_block(src.readlines()))
+    bsd_2_clause.register(copyrights_by_license.get("BSD-2-Clause", []))
+
+
+class PackageManualBuilder(SphinxBuilder):
+    """ Builds the package user manual. """
+
+    def __init__(self, director: PackageBuildDirector, item: Item):
+        super().__init__(director, item)
+        self._membench: Dict[str, Any] = {}
+        my_type = self.item.type
+        self.mapper.add_get_value(f"{my_type}:/archive-file",
+                                  self._get_archive_file)
+        self.mapper.add_get_value(f"{my_type}:/archive-sha512",
+                                  self._get_archive_sha512)
+        self.mapper.add_get_value(f"{my_type}:/benchmark-variants-list",
+                                  self._get_benchmark_variants_list)
+        self.mapper.add_get_value(f"{my_type}:/memory-benchmarks",
+                                  self._get_membench)
+        self.mapper.add_get_value(f"{my_type}:/memory-benchmark-section",
+                                  self._get_membench_section)
+        self.mapper.add_get_value(
+            f"{my_type}:/memory-benchmark-compare-section",
+            self._get_membench_compare_section)
+        self.mapper.add_get_value(
+            f"{my_type}:/memory-benchmark-variants-table",
+            self._get_membench_variants_table)
+        self.mapper.add_get_value(f"{my_type}:/performance-variants-table",
+                                  self._get_performance_variants_table)
+        self.mapper.add_get_value(f"{my_type}:/pkg-config",
+                                  self._get_pkg_config)
+        self.mapper.add_get_value(f"{my_type}:/pre-qualified-interfaces",
+                                  self._get_pre_qualified_interfaces)
+        self.mapper.add_get_value(f"{my_type}:/repositories", self._get_repos)
+        self.mapper.add_get_value(f"{my_type}:/verify-package-file",
+                                  self._get_verify_pkg_file)
+        self.mapper.add_get_value(f"{my_type}:/verify-package-help",
+                                  self._get_verify_pkg_help)
+        self.mapper.add_get_value(f"{my_type}:/verify-package-sha512",
+                                  self._get_verify_pkg_sha512)
+        self.mapper.add_get_value(f"{my_type}:/change-list",
+                                  self._get_change_list)
+        self.mapper.add_get_value(f"{my_type}:/open-issues",
+                                  self._get_open_issues)
+        self.mapper.add_get_value(f"{my_type}:/license-info",
+                                  self._get_license_info)
+        self.mapper.add_get_value(f"{my_type}:/targets", self._get_targets)
+        for name in [my_type, "qdp/sphinx-section"]:
+            self.mapper.add_get_value(f"{name}:/make", self._get_make)
+            self.mapper.add_get_value(f"{name}:/object-size",
+                                      self._get_object_size)
+
+    def run(self) -> None:
+        membench = self.input("membench-results")
+        assert isinstance(membench, DirectoryState)
+        self._membench = membench.json_load()
+        super().run()
+
+    def _get_archive_file(self, _ctx: ItemGetValueContext) -> Any:
+        archive = self.input("archive")
+        assert isinstance(archive, DirectoryState)
+        return os.path.basename(archive.file)
+
+    def _get_archive_sha512(self, _ctx: ItemGetValueContext) -> Any:
+        archive = self.input("archive")
+        assert isinstance(archive, DirectoryState)
+        _, digest = next(archive.files_and_hashes())
+        return _format_digest(digest)
+
+    def _get_make(self, ctx: ItemGetValueContext) -> Any:
+        assert ctx.args
+        dirs, make_args = ctx.args.split(" ", 1)
+        make_list = make_args.split(",")
+        cwd = self.substitute("${/qdp/variant:/deployment-directory}/") + dirs
+        for targets in make_list[:-1]:
+            status = run_command(["make"] + _make_targets(targets), cwd=cwd)
+            assert status == 0
+        stdout: List[str] = []
+        status = run_command(["make"] + _make_targets(make_list[-1]),
+                             cwd=cwd,
+                             stdout=stdout)
+        assert status == 0
+        return _make_code_block(stdout)
+
+    def _get_benchmark_variants_list(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            for variant in self["benchmark-variants"]:
+                content.add_definition_item(variant["name"],
+                                            variant["description"])
+            return "\n".join(content)
+
+    def _get_membench(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            label = self["memory-benchmark-build-label"]
+            sections_by_uid = self._membench[label]["membench"]
+            root = self.item.cache["/rtems/req/mem-basic"]
+            table_pivots = ["/rtems/req/mem-smp-1"]
+            generate(content, sections_by_uid, root, table_pivots,
+                     SphinxMapper(root))
+            return "\n".join(content)
+
+    def _get_membench_section(self, ctx: ItemGetValueContext) -> Any:
+        assert ctx.args
+        uid, section = ctx.args.split(":")
+        item = self.item.cache[uid]
+        label = self["memory-benchmark-build-label"]
+        sections = self._membench[label]["membench"][item.uid]
+        return str(sections[section])
+
+    def _get_membench_compare_section(self, ctx: ItemGetValueContext) -> Any:
+        assert ctx.args
+        uid, other_uid, section = ctx.args.split(":")
+        item = self.item.cache[uid]
+        label = self["memory-benchmark-build-label"]
+        sections = self._membench[label]["membench"][item.uid]
+        other_item = self.item.cache[other_uid]
+        other_sections = self._membench[label]["membench"][other_item.uid]
+        return f"{other_sections[section] - sections[section]:+}"
+
+    def _get_membench_variants_table(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            root = self.item.cache["/rtems/req/mem-basic"]
+            variants: List[MembenchVariant] = []
+            for variant in self["benchmark-variants"]:
+                variant_label = variant["build-label"]
+                if variant_label not in self._membench:
+                    continue
+                variants.append(MembenchVariant(variant["name"],
+                                                variant_label))
+            generate_variants_table(content, self._membench, root, variants)
+            return "\n".join(content)
+
+    def _get_measurements_by_variant(self) -> Dict[int, _Measurements]:
+        measurements_by_variant: Dict[int, _Measurements] = {}
+        for index, variant in enumerate(self["benchmark-variants"]):
+            test_log = self.director[self.item.to_abs_uid(
+                variant["test-log-uid"])]
+            measurements: _Measurements = {}
+            if not test_log.item.enabled:
+                if index == 0:
+                    break
+                measurements_by_variant[index] = measurements
+                continue
+            assert isinstance(test_log, DirectoryState)
+            with open(test_log.file, "r", encoding="utf-8") as src:
+                data = json.load(src)
+            for report in data["reports"]:
+                for test_case in report.get("test-suite",
+                                            {}).get("test-cases", []):
+                    for measurement in test_case["runtime-measurements"]:
+                        stats = (measurement["min"], measurement["q2"],
+                                 measurement["max"])
+                        measurements.setdefault(
+                            measurement["name"],
+                            {})[measurement["variant"]] = stats
+            measurements_by_variant[index] = measurements
+        return measurements_by_variant
+
+    def _make_performance_variants_rows(
+        self, item: Item, envs: List[str], env_links: Dict[str, str],
+        measurements_by_variant: Dict[int, _Measurements]
+    ) -> List[Tuple[str, ...]]:
+        rows: List[Tuple[str, ...]] = []
+        info_spec = item.spec
+        for env in envs:
+            env_link = env_links[env.split("/")[0]]
+            info_env = f"`{env} <{env_link}>`__"
+            for index, variant in enumerate(self["benchmark-variants"]):
+                stats = measurements_by_variant[index].get(item.ident,
+                                                           {}).get(env, None)
+                info = (info_spec, info_env, variant["name"])
+                if index == 0:
+                    assert stats
+                    base = stats
+                    rows.append(info + tuple(f"{value * 1e6:.3f}"
+                                             for value in stats))
+                elif stats:
+                    rows.append(info + tuple(
+                        f"{(value - base[j]) / base[j] * 100.0:+.3g} %"
+                        for j, value in enumerate(stats)))
+                else:
+                    rows.append(info + ("?", "?", "?"))
+                info_spec = ""
+                info_env = ""
+        return rows
+
+    def _get_performance_variants_table(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            measurements_by_variant = self._get_measurements_by_variant()
+            if not measurements_by_variant:
+                return "There is no performance variants table available."
+            items: Set[Item] = set()
+            _gather_runtime_performance_items(items,
+                                              self.item.cache["/req/root"])
+            envs = list(measurements_by_variant[0][next(
+                iter(items)).ident].keys())
+            envs.sort(key=_environment_order)
+            req_path = self.substitute(
+                "${/qdp/variant:/deployment-directory}/doc/ts/srs/"
+                "html/requirements.html#spec-req-perf-runtime-environment-")
+            env_links = {
+                "HotCache": f"{req_path}hot-cache",
+                "FullCache": f"{req_path}full-cache",
+                "DirtyCache": f"{req_path}dirty-cache",
+                "Load": f"{req_path}load"
+            }
+            rows: List[Tuple[str, ...]] = [
+                ("Specification", "Environment", "Variant", "Min [μs]",
+                 "Median [μs]", "Max [μs]")
+            ]
+            for item in sorted(items):
+                rows.extend(
+                    self._make_performance_variants_rows(
+                        item, envs, env_links, measurements_by_variant))
+            content = SphinxContent(section_level=section_level)
+            with content.latex_tiny("scriptsize"):
+                content.add_grid_table(rows, [31, 14, 19, 12, 12, 12])
+            return "\n".join(content)
+
+    def _get_pkg_config(self, _ctx: ItemGetValueContext) -> Any:
+        pkg = self.substitute(
+            "${/qdp/variant:/deployment-directory}/lib/pkgconfig/"
+            "${/qdp/variant:/arch}-rtems${/qdp/variant:/rtems-version}-"
+            "${/qdp/variant:/bsp}-qual-only.pc")
+        content = SphinxContent()
+        with content.directive("code-block", value="none"):
+            _run_pkg_config(content, ["--variable=ABI_FLAGS", pkg])
+            _run_pkg_config(content, ["--cflags", pkg])
+            _run_pkg_config(content, ["--libs", pkg])
+        return "\n".join(content)
+
+    def _get_pre_qualified_interfaces(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            items: Dict[str, List[Item]] = {}
+            gather_api_items(self.item.cache, items)
+            for group, group_items in sorted(items.items()):
+                with content.section(group):
+                    content.add_list(item["name"] for item in group_items)
+            return "\n".join(content)
+
+    def _get_repos(self, ctx: ItemGetValueContext) -> Any:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            variant = self.item.map("/qdp/variant")
+            prefix = self.substitute("${/qdp/variant:/deployment-directory}")
+            for item in variant.children("repository"):
+                step = self.director[item.uid]
+                origin_branch = step["origin-branch"]
+                origin_commit = step["origin-commit"]
+                if origin_branch and origin_commit:
+                    dest = os.path.relpath(step["directory"], prefix)
+                    with content.section(f"Git Repository: {dest}"):
+                        content.add(step["description"])
+                        content.add(f"""The ``{step["branch"]}`` branch with
+commit ``{step["commit"]}``
+was used to build the QDP.  This branch is checked out after unpacking the
+archive.  It is based on
+commit `{origin_commit} <{step['origin-commit-url']}>`_
+of the ``{origin_branch}`` branch of the ``origin`` remote repository.""")
+            return "\n".join(content)
+
+    def _get_object_size(self, ctx: ItemGetValueContext) -> Any:
+        assert ctx.args
+        label = self["memory-benchmark-build-label"]
+        return str(self._membench[label]["object-sizes"][ctx.args])
+
+    def _get_verify_pkg_file(self, _ctx: ItemGetValueContext) -> Any:
+        verify_package = self.input("verify-package")
+        assert isinstance(verify_package, DirectoryState)
+        return os.path.basename(verify_package.file)
+
+    def _get_verify_pkg_help(self, _ctx: ItemGetValueContext) -> Any:
+        content = SphinxContent()
+        with content.directive("code-block", value="none"):
+            verify_package = self.input("verify-package")
+            assert isinstance(verify_package, DirectoryState)
+            cmd = [verify_package.file, "--help"]
+            content.add([
+                f"$$ cd {os.path.dirname(cmd[0])}",
+                f"$$ ./{os.path.basename(cmd[0])} --help"
+            ])
+            stdout: List[str] = []
+            status = run_command(cmd, stdout=stdout)
+            assert status == 0
+            content.append(stdout)
+        return "\n".join(content)
+
+    def _get_verify_pkg_sha512(self, _ctx: ItemGetValueContext) -> Any:
+        verify_package = self.input("verify-package")
+        assert isinstance(verify_package, DirectoryState)
+        _, digest = next(verify_package.files_and_hashes())
+        return _format_digest(digest)
+
+    def _get_change_list(self, ctx: ItemGetValueContext) -> str:
+        with self.section_level(ctx) as (section_level, _):
+            changes = self.input("package-changes")
+            assert isinstance(changes, PackageChanges)
+            return changes.get_change_list(section_level)
+
+    def _get_open_issues(self, ctx: ItemGetValueContext) -> str:
+        with self.section_level(ctx) as (section_level, _):
+            changes = self.input("package-changes")
+            assert isinstance(changes, PackageChanges)
+            return changes.get_open_issues(section_level)
+
+    def _get_license_info(self, ctx: ItemGetValueContext) -> str:
+        archive = self.input("archive")
+        assert isinstance(archive, DirectoryState)
+        archiver = self.director[archive.item.child("output").uid]
+        assert isinstance(archiver, Archiver)
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            bsd_2_clause = Copyrights()
+            deployment_directory = self.substitute(
+                "${/qdp/variant:/deployment-directory}")
+            content.add(f"""All directories and file paths in this section are
+relative to :file:`{_format_path(deployment_directory)}`.""")
+            for member in archiver.inputs("member"):
+                assert isinstance(member, DirectoryState)
+                _add_licenses(content, deployment_directory, member,
+                              bsd_2_clause)
+            if bsd_2_clause:
+                with content.section("BSD-2-Clause copyrights"):
+                    content.add(bsd_2_clause.get_statements("| ©"))
+                    content.add(
+                        _make_code_block(BSD_2_CLAUSE_LICENSE.split("\n")))
+            return "\n".join(content)
+
+    def _get_targets(self, ctx: ItemGetValueContext) -> str:
+        with self.section_level(ctx) as (section_level, _):
+            content = SphinxContent(section_level=section_level)
+            for target in sorted(
+                    self.item.cache.items_by_type.get(
+                        "requirement/non-functional/design-target", [])):
+                if not target.enabled:
+                    continue
+                with content.section(target["name"]):
+                    content.add(target["brief"])
+                    content.add(target["description"])
+            return "\n".join(content)
diff --git a/rtemsspec/rtems.py b/rtemsspec/rtems.py
index 735880c5..4353f658 100644
--- a/rtemsspec/rtems.py
+++ b/rtemsspec/rtems.py
@@ -29,9 +29,11 @@ import hashlib
 import itertools
 from typing import Any, Dict, List, Set, Tuple, Union
 
-from rtemsspec.items import create_unique_link, Item, ItemCache, Link
+from rtemsspec.items import create_unique_link, Item, ItemCache, \
+    ItemGetValueContext, ItemMapper, Link
 from rtemsspec.glossary import augment_glossary_terms
-from rtemsspec.packagebuild import BuildItem, PackageBuildDirector
+from rtemsspec.packagebuild import BuildItem, BuildItemFactory, \
+    PackageBuildDirector
 from rtemsspec.validation import augment_with_test_case_links
 
 _NOT_PRE_QUALIFIED = set([
@@ -296,12 +298,26 @@ def _is_proxy_link_enabled(link: Link) -> bool:
     return link.item.is_enabled(link.item.cache.enabled)
 
 
+def _get_issue(ctx: ItemGetValueContext) -> Any:
+    database = ctx.item.parent("issue-member")
+    mapper = ItemMapper(ctx.item)
+    url = mapper.substitute(database["url"])
+    identifier = mapper.substitute(database["format-identifier"])
+    return f"`{database['name']} {identifier} <{url}>`__"
+
+
 class RTEMSItemCache(BuildItem):
     """
     This build step augments the items with RTEMS-specific attributes and
     links.
     """
 
+    @classmethod
+    def prepare_factory(cls, factory: BuildItemFactory,
+                        type_name: str) -> None:
+        BuildItem.prepare_factory(factory, type_name)
+        factory.add_get_value("qdp/issue:/name", _get_issue)
+
     def __init__(self, director: PackageBuildDirector, item: Item):
         super().__init__(director, item)
         self.item_cache = self.item.cache
diff --git a/rtemsspec/sreldbuilder.py b/rtemsspec/sreldbuilder.py
new file mode 100644
index 00000000..98fd9d6f
--- /dev/null
+++ b/rtemsspec/sreldbuilder.py
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: BSD-2-Clause
+""" Builds the software release document (SRelD). """
+
+# Copyright (C) 2023 embedded brains GmbH & Co. KG
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from rtemsspec.items import Item, ItemGetValueContext
+from rtemsspec.packagebuild import PackageBuildDirector
+from rtemsspec.packagechanges import PackageChanges
+from rtemsspec.sphinxbuilder import SphinxBuilder
+
+
+class SRelDBuilder(SphinxBuilder):
+    """ Builds the software release document (SRelD). """
+
+    def __init__(self, director: PackageBuildDirector, item: Item):
+        super().__init__(director, item)
+        my_type = self.item.type
+        self.mapper.add_get_value(f"{my_type}:/changes", self._get_changes)
+        self.mapper.add_get_value(f"{my_type}:/issues", self._get_issues)
+
+    def _get_changes(self, _ctx: ItemGetValueContext) -> str:
+        changes = self.input("package-changes")
+        assert isinstance(changes, PackageChanges)
+        return changes.get_current_changes()
+
+    def _get_issues(self, ctx: ItemGetValueContext) -> str:
+        with self.section_level(ctx) as (section_level, _):
+            changes = self.input("package-changes")
+            assert isinstance(changes, PackageChanges)
+            return changes.get_current_issues(section_level)
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/build/disabled.yml b/rtemsspec/tests/spec-packagebuild/qdp/build/disabled.yml
new file mode 100644
index 00000000..dd02ea89
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/build/disabled.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}
+directory-state-type: generic
+enabled-by: false
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/build/doc-ddf-sreld.yml b/rtemsspec/tests/spec-packagebuild/qdp/build/doc-ddf-sreld.yml
new file mode 100644
index 00000000..7ba058de
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/build/doc-ddf-sreld.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/doc-ddf-sreld
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/build/doc-package-manual.yml b/rtemsspec/tests/spec-packagebuild/qdp/build/doc-package-manual.yml
new file mode 100644
index 00000000..dff94d6a
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/build/doc-package-manual.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/doc-package-manual
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-ddf-sreld.yml b/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-ddf-sreld.yml
new file mode 100644
index 00000000..d8eb494b
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-ddf-sreld.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/deployment-directory}/doc-ddf-sreld
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-package-manual.yml b/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-package-manual.yml
new file mode 100644
index 00000000..213b23d4
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/deployment/doc-package-manual.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/deployment-directory}/doc-package-manual
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2189.yml b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2189.yml
new file mode 100644
index 00000000..23828c53
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2189.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights: []
+created: '2019-04-02T15:06:29.497Z'
+enabled-by: true
+identifier: '2189'
+labels: []
+links:
+- role: issue-member
+  uid: database
+milestone: null
+qdp-type: issue
+status: assigned
+subject: Insufficient documentation for rtems_clock_get_tod()
+type: qdp
+updated: '2019-04-02T15:06:29.497Z'
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2365.yml b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2365.yml
new file mode 100644
index 00000000..6eb59a51
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2365.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+created: '2019-04-02T15:06:29.497Z'
+copyrights: []
+enabled-by: true
+identifier: '2365'
+labels: []
+links:
+- role: issue-member
+  uid: database
+milestone: null
+qdp-type: issue
+status: assigned
+subject: Task pre-emption disable is broken due to pseudo ISR tasks
+type: qdp
+updated: '2019-04-02T15:06:29.497Z'
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2548.yml b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2548.yml
new file mode 100644
index 00000000..ab099623
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/2548.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+created: '2019-04-02T15:06:29.497Z'
+copyrights: []
+enabled-by: true
+identifier: '2548'
+labels: []
+links:
+- role: issue-member
+  uid: database
+milestone: null
+qdp-type: issue
+status: assigned
+subject: Problematic integer conversion in rtems_clock_get_tod()
+type: qdp
+updated: '2019-04-02T15:06:29.497Z'
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/database.yml b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/database.yml
new file mode 100644
index 00000000..93617b81
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/issue/rtems/database.yml
@@ -0,0 +1,10 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+format-identifier: '#${.:/identifier}'
+links: []
+name: RTEMS Ticket
+qdp-type: issue-database
+type: qdp
+url: https://devel.rtems.org/ticket/${.:/identifier}
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
index 4147fd6f..7ec67413 100644
--- a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
@@ -25,7 +25,11 @@ links:
   uid: steps/doc
 - role: build-step
   uid: steps/doc-2
+- role: build-step
+  uid: steps/doc-ddf-sreld
 - role: build-step
   uid: steps/archive
+- role: build-step
+  uid: steps/doc-package-manual
 qdp-type: package-build
 type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-changes.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-changes.yml
new file mode 100644
index 00000000..7819522e
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-changes.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+change-list:
+- description: |
+    Description 1.
+  name: Name 1
+  package-status: package-status/test-1
+- description: |
+    Description 2.
+  name: Name 2
+  package-status: package-status/test-2
+links: []
+qdp-type: package-changes
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-1.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-1.yml
new file mode 100644
index 00000000..612c6e12
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-1.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: issue
+  status: open
+  uid: ../issue/rtems/2189
+- role: issue
+  status: open
+  uid: ../issue/rtems/2365
+qdp-type: package-status
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-2.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-2.yml
new file mode 100644
index 00000000..42fc5c2e
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-status/test-2.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: issue
+  status: closed
+  uid: ../issue/rtems/2189
+- role: issue
+  status: open
+  uid: ../issue/rtems/2365
+- role: issue
+  status: open
+  uid: ../issue/rtems/2548
+qdp-type: package-status
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/repo/a.yml b/rtemsspec/tests/spec-packagebuild/qdp/repo/a.yml
new file mode 100644
index 00000000..0cf7de1a
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/repo/a.yml
@@ -0,0 +1,22 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+branch: qdp
+commit: a412700fd90e6195c255aea2048ae2ef37244df5
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+description: A
+directory: ${../variant:/deployment-directory}/build/src/a
+directory-state-type: repository
+enabled-by: true
+files: []
+hash: null
+links:
+- role: repository
+  uid: ../variant
+origin-branch: null
+origin-commit: null
+origin-commit-url: null
+origin-url: null
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/repo/b.yml b/rtemsspec/tests/spec-packagebuild/qdp/repo/b.yml
new file mode 100644
index 00000000..e40a6f58
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/repo/b.yml
@@ -0,0 +1,22 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+branch: qdp
+commit: 52f06822b8921ad825cb593b792eab7640e26cde
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+description: B
+directory: ${../variant:/deployment-directory}/build/src/b
+directory-state-type: repository
+enabled-by: true
+files: []
+hash: null
+links:
+- role: repository
+  uid: ../variant
+origin-branch: master
+origin-commit: bcef89f2360b97005e490c92fe624ab9dec789e6
+origin-commit-url: https://git.rtems.org/rtems/commit/?id=${.:/origin-commit}
+origin-url: git://git.rtems.org/rtems.git
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/source/a.yml b/rtemsspec/tests/spec-packagebuild/qdp/source/a.yml
index 498a5546..049202ce 100644
--- a/rtemsspec/tests/spec-packagebuild/qdp/source/a.yml
+++ b/rtemsspec/tests/spec-packagebuild/qdp/source/a.yml
@@ -1,7 +1,11 @@
 SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
 copyrights:
 - Copyright (C) 2023 embedded brains GmbH & Co. KG
-copyrights-by-license: {}
+copyrights-by-license:
+  BSD-2-Clause:
+  - Copyright (C) 2023 Alice
+  files:
+  - dir/a.txt
 directory: ${../variant:/prefix-directory}
 directory-state-type: generic
 enabled-by: true
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/source/archive.yml b/rtemsspec/tests/spec-packagebuild/qdp/source/archive.yml
new file mode 100644
index 00000000..4361edca
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/source/archive.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/prefix-directory}
+directory-state-type: generic
+enabled-by: true
+files:
+- file: archive.tar.xz
+  hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/source/doc-ddf-sreld.yml b/rtemsspec/tests/spec-packagebuild/qdp/source/doc-ddf-sreld.yml
new file mode 100644
index 00000000..e08c4301
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/source/doc-ddf-sreld.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/src/doc-ddf-sreld
+directory-state-type: generic
+enabled-by: true
+files:
+- file: index.rst
+  hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/source/doc-package-manual.yml b/rtemsspec/tests/spec-packagebuild/qdp/source/doc-package-manual.yml
new file mode 100644
index 00000000..366e6f7f
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/source/doc-package-manual.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/src/doc-package-manual
+directory-state-type: generic
+enabled-by: true
+files:
+- file: index.rst
+  hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/steps/archive-2.yml b/rtemsspec/tests/spec-packagebuild/qdp/steps/archive-2.yml
new file mode 100644
index 00000000..726a1796
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/steps/archive-2.yml
@@ -0,0 +1,23 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+archive-file: archive.tar.xz
+archive-strip-prefix: ${../variant:/prefix-directory}/
+build-step-type: archive
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+description: |
+  Description.
+enabled-by: true
+links:
+- hash: null
+  name: member
+  role: input
+  uid: ../source/a
+- name: archive
+  role: output
+  uid: ../source/archive
+- name: verify-package
+  role: output
+  uid: ../deployment/verify-package
+qdp-type: build-step
+type: qdp
+verification-script: verify_package.py
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-ddf-sreld.yml b/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-ddf-sreld.yml
new file mode 100644
index 00000000..c3c4269f
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-ddf-sreld.yml
@@ -0,0 +1,47 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-step-type: sphinx
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+description: |
+  Builds the SRelD.
+document-type: ddf-sreld
+document-title: SRelD
+document-toctree-maxdepth: 4
+document-html-help-base-name: SRelD
+document-components:
+- action: copy-and-substitute
+  add-to-index: false
+  source: index.rst
+  destination: source/index.rst
+document-contract: Contract
+document-key: blub
+document-releases: []
+document-contributors: []
+document-copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+document-license: CC-BY-SA-4.0
+document-license-map: {}
+enabled-by: ddf-sreld
+links:
+- hash: null
+  name: spec
+  role: input
+  uid: rtems-item-cache
+- hash: null
+  name: package-changes
+  role: input
+  uid: ../package-changes
+- hash: null
+  name: source
+  role: input
+  uid: ../source/doc-ddf-sreld
+- name: destination
+  role: output
+  uid: ../deployment/doc-ddf-sreld
+- name: build
+  role: output
+  uid: ../build/doc-ddf-sreld
+output-html: null
+output-pdf: null
+qdp-type: build-step
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-package-manual.yml b/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-package-manual.yml
new file mode 100644
index 00000000..1e812b71
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/steps/doc-package-manual.yml
@@ -0,0 +1,84 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-step-type: sphinx
+benchmark-variants:
+- description:
+    Description 1
+  build-label: arch/bsp
+  name: Name 1
+  test-log-uid: ../test-logs/perf
+- description: |
+    Description 2
+  build-label: arch/bsp
+  name: Name 2
+  test-log-uid: ../test-logs/perf
+- description: |
+    Description 3
+  build-label: arch/bsp
+  name: Name 3
+  test-log-uid: ../build/disabled
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+description: |
+  Builds the package manual.
+document-type: package-manual
+document-title: Package Manual
+document-toctree-maxdepth: 4
+document-html-help-base-name: PM
+document-components:
+- action: add-to-index
+  add-to-index: true
+  destination: source/glossary.rst
+- action: copy-and-substitute
+  add-to-index: false
+  source: index.rst
+  destination: source/index.rst
+- action: glossary
+  add-to-index: false
+  destination: source/glossary.rst
+  glossary-groups:
+  - /glossary-general
+document-contract: Contract
+document-copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+document-key: blub
+document-releases: []
+document-contributors: []
+enabled-by: package-manual
+links:
+- hash: null
+  name: spec
+  role: input
+  uid: rtems-item-cache
+- hash: null
+  name: membench-results
+  role: input
+  uid: ../test-logs/membench-2
+- hash: null
+  name: package-changes
+  role: input
+  uid: ../package-changes
+- hash: null
+  name: source
+  role: input
+  uid: ../source/doc-package-manual
+- hash: null
+  name: archive
+  role: input
+  uid: ../source/archive
+- hash: null
+  name: verify-package
+  role: input
+  uid: ../deployment/verify-package
+- name: destination
+  role: output
+  uid: ../deployment/doc-package-manual
+- name: build
+  role: output
+  uid: ../build/doc-package-manual
+document-license: CC-BY-SA-4.0
+document-license-map: {}
+memory-benchmark-build-label: arch/bsp
+output-html: null
+output-pdf: null
+qdp-type: build-step
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/test-logs/membench-2.yml b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/membench-2.yml
new file mode 100644
index 00000000..21979ff0
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/membench-2.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/build-directory}/src
+directory-state-type: generic
+enabled-by: true
+files:
+- file: membench.json
+  hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/test-logs/perf.yml b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/perf.yml
new file mode 100644
index 00000000..66a89a4e
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/test-logs/perf.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/deployment-directory}
+directory-state-type: test-log
+enabled-by: true
+files:
+- file: test-log-perf.json
+  hash: null
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/req/api.yml b/rtemsspec/tests/spec-packagebuild/req/api.yml
new file mode 100644
index 00000000..3c3d4626
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/req/api.yml
@@ -0,0 +1,14 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: requirement-refinement
+  uid: root
+non-functional-type: interface-requirement
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The software product shall provide an API.
+type: requirement
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/group.yml b/rtemsspec/tests/spec-packagebuild/rtems/group.yml
index 7f7864b7..60560a04 100644
--- a/rtemsspec/tests/spec-packagebuild/rtems/group.yml
+++ b/rtemsspec/tests/spec-packagebuild/rtems/group.yml
@@ -12,7 +12,7 @@ links:
 - role: interface-placement
   uid: header
 - role: requirement-refinement
-  uid: ../req/root
+  uid: ../req/api
 name: Name
 text: |
   Text.
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/req/mem-basic.yml b/rtemsspec/tests/spec-packagebuild/rtems/req/mem-basic.yml
new file mode 100644
index 00000000..f04e03a9
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/rtems/req/mem-basic.yml
@@ -0,0 +1,15 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: requirement-refinement
+  uid: ../group
+non-functional-type: quality
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The system shall provide a benchmark program to show the static memory usage
+  of a basic application configuration.
+type: requirement
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/req/perf.yml b/rtemsspec/tests/spec-packagebuild/rtems/req/perf.yml
new file mode 100644
index 00000000..9fd145a9
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/rtems/req/perf.yml
@@ -0,0 +1,25 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: requirement-refinement
+  uid: ../group
+non-functional-type: performance-runtime
+params: {}
+rationale: null
+references: []
+requirement-type: non-functional
+test-body:
+  brief: |
+    Brief.
+  code: |
+    code();
+  description: null
+test-cleanup: null
+test-prepare: null
+test-setup: null
+test-teardown: null
+text: |
+  Text.
+type: requirement
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/target-a.yml b/rtemsspec/tests/spec-packagebuild/rtems/target-a.yml
new file mode 100644
index 00000000..cd2b1ea3
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/rtems/target-a.yml
@@ -0,0 +1,19 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+brief: |
+  Brief target A.
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+description: |
+  Description target A.
+links:
+- role: requirement-refinement
+  uid: ../req/root
+name: Name Target A
+non-functional-type: design-target
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The ${.:/name} shall be a target.
+type: requirement
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/target-b.yml b/rtemsspec/tests/spec-packagebuild/rtems/target-b.yml
new file mode 100644
index 00000000..0b61c867
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/rtems/target-b.yml
@@ -0,0 +1,19 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+brief: |
+  Brief target B.
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: target-b
+description: |
+  Description target B.
+links:
+- role: requirement-refinement
+  uid: ../req/root
+name: Name Target B
+non-functional-type: design-target
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The ${.:/name} shall be a target.
+type: requirement
diff --git a/rtemsspec/tests/spec-packagebuild/rtems/val/mem-basic.yml b/rtemsspec/tests/spec-packagebuild/rtems/val/mem-basic.yml
new file mode 100644
index 00000000..8cfcd1cf
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/rtems/val/mem-basic.yml
@@ -0,0 +1,54 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH & Co. KG
+enabled-by: true
+links: []
+test-brief: |
+  This static memory usage benchmark program facilitates a basic application
+  configuration.
+test-code: |
+  static void Init( rtems_task_argument arg )
+  {
+    (void) arg;
+
+    /* Nothing to do */
+  }
+
+  #define TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
+
+  #define TASK_STORAGE_SIZE \
+    RTEMS_TASK_STORAGE_SIZE( \
+      RTEMS_MINIMUM_STACK_SIZE, \
+      TASK_ATTRIBUTES   )
+
+  #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+
+  #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 0
+
+  #define CONFIGURE_DISABLE_NEWLIB_REENTRANCY
+
+  #define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM
+
+  #define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+
+  #define CONFIGURE_MAXIMUM_TASKS 1
+
+  #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+  #define CONFIGURE_INIT_TASK_ATTRIBUTES TASK_ATTRIBUTES
+
+  #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
+
+  #define CONFIGURE_INIT_TASK_CONSTRUCT_STORAGE_SIZE TASK_STORAGE_SIZE
+
+  #define CONFIGURE_INIT
+
+  #include <rtems/confdefs.h>
+test-description: |
+  This resource benchmark is configured for exactly one processor, no clock
+  driver, no Newlib reentrancy support, and no file system.
+test-includes:
+- rtems.h
+test-local-includes: []
+test-target: mem-rtems-basic.c
+type: memory-benchmark
diff --git a/rtemsspec/tests/test-files/pkg/build/src/doc-ddf-sreld/index.rst b/rtemsspec/tests/test-files/pkg/build/src/doc-ddf-sreld/index.rst
new file mode 100644
index 00000000..7df5827a
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/build/src/doc-ddf-sreld/index.rst
@@ -0,0 +1,6 @@
+.. SPDX-License-Identifier: CC-BY-SA-4.0
+
+.. Copyright (C) 2023 embedded brains GmbH & Co. KG
+
+${.:/changes}
+${.:/issues}
diff --git a/rtemsspec/tests/test-files/pkg/build/src/doc-package-manual/index.rst b/rtemsspec/tests/test-files/pkg/build/src/doc-package-manual/index.rst
new file mode 100644
index 00000000..8279d40b
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/build/src/doc-package-manual/index.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: CC-BY-SA-4.0
+
+.. Copyright (C) 2023 embedded brains GmbH & Co. KG
+
+${.:/archive-file}
+${.:/archive-sha512}
+${.:/pkg-config}
+${.:/verify-package-file}
+${.:/verify-package-help}
+${.:/verify-package-sha512}
+${.:/make:dir super clean,}
+${.:/object-size:/rtems/task/obj}
+${.:/benchmark-variants-list}
+${.:/memory-benchmarks}
+${.:/memory-benchmark-section:/rtems/val/mem-basic:.text}
+${.:/memory-benchmark-compare-section:/rtems/val/mem-basic:/rtems/val/mem-basic:.text}
+${.:/memory-benchmark-variants-table}
+${.:/performance-variants-table}
+${.:/clear-benchmark-variants}
+${.:/memory-benchmark-variants-table}
+${.:/performance-variants-table}
+${.:/repositories}
+${.:/pre-qualified-interfaces}
+${.:/targets}
+${.:/change-list}
+${.:/open-issues}
+${.:/license-info}
+${.:/clear-copyrights-by-license}
+${.:/license-info}
diff --git a/rtemsspec/tests/test-files/pkg/build/src/membench.json b/rtemsspec/tests/test-files/pkg/build/src/membench.json
new file mode 100644
index 00000000..69b27a5f
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/build/src/membench.json
@@ -0,0 +1,16 @@
+{
+  "arch/bsp": {
+    "membench": {
+      "/rtems/val/mem-basic": {
+        ".bss": 0,
+        ".data": 8,
+        ".noinit": 1,
+        ".rodata": 5,
+        ".text": 123
+      }
+    },
+    "object-sizes": {
+      "/rtems/task/obj": 4
+    }
+  }
+}
diff --git a/rtemsspec/tests/test-files/pkg/test-log-perf.json b/rtemsspec/tests/test-files/pkg/test-log-perf.json
new file mode 100644
index 00000000..85b30111
--- /dev/null
+++ b/rtemsspec/tests/test-files/pkg/test-log-perf.json
@@ -0,0 +1,637 @@
+{
+  "duration": 272.82567146699876,
+  "end-time": "2023-07-11T09:52:01.875951",
+  "reports": [
+    {
+      "command-line": [],
+      "data-ranges": [],
+      "executable": "ts-performance-no-clock-0.exe",
+      "executable-sha512": "EgqXYmQTKT8anJjQCs7OW4S51KtKc4eoGi5G6y8Q_ZakVWGCy_Yf2VuxMgIVDGeljyrhin76CNppSg_T_Y-plw==",
+      "info": {
+        "build": [],
+        "line-begin-of-test": 84,
+        "line-build": 87,
+        "line-end-of-test": 2443,
+        "line-state": 86,
+        "line-tools": 88,
+        "line-version": 85,
+        "name": "TestsuitesPerformanceNoClock0",
+        "state": "EXPECTED_PASS",
+        "tools": "13.2.0",
+        "version": "6.0.0.8c9a5d0e1eae450dd28344be9390936a4573740d"
+      },
+      "output": [
+        "*** BEGIN OF TEST TestsuitesPerformanceNoClock0 ***",
+        "*** TEST VERSION: 6.0.0.8c9a5d0e1eae450dd28344be9390936a4573740d",
+        "*** TEST STATE: EXPECTED_PASS",
+        "*** TEST BUILD:",
+        "*** TEST TOOLS: 13.2.0",
+        "A:TestsuitesPerformanceNoClock0",
+        "S:Platform:RTEMS",
+        "S:Compiler:13.2.0",
+        "S:Version:6.0.0.8c9a5d0e1eae450dd28344be9390936a4573740d",
+        "S:BSP:gr712rc",
+        "S:BuildLabel:sparc/gr712rc/uni/6/qual-only",
+        "S:TargetHash:SHA256:cpI09Ju6orF2eoJcmJi4igeIarypsRNwUxTrZSs9LMg=",
+        "S:RTEMS_DEBUG:0",
+        "S:RTEMS_MULTIPROCESSING:0",
+        "S:RTEMS_POSIX_API:0",
+        "S:RTEMS_PROFILING:0",
+        "S:RTEMS_SMP:0",
+        "B:ScoreCpuValPerf",
+        "M:B:RtemsReqPerf",
+        "M:V:FullCache",
+        "M:N:100",
+        "M:S:99:0.000000275",
+        "M:S:1:0.000000475",
+        "M:MI:0.000000275",
+        "M:P1:0.000000275",
+        "M:Q1:0.000000275",
+        "M:Q2:0.000000275",
+        "M:Q3:0.000000275",
+        "M:P99:0.000000475",
+        "M:MX:0.000000475",
+        "M:MAD:0.000000000",
+        "M:D:0.000027697",
+        "M:E:RtemsReqPerf:D:0.007165362",
+        "M:B:RtemsReqPerf",
+        "M:V:HotCache",
+        "M:N:100",
+        "M:S:100:0.000000275",
+        "M:MI:0.000000275",
+        "M:P1:0.000000275",
+        "M:Q1:0.000000275",
+        "M:Q2:0.000000275",
+        "M:Q3:0.000000275",
+        "M:P99:0.000000275",
+        "M:MX:0.000000275",
+        "M:MAD:0.000000000",
+        "M:D:0.000027497",
+        "M:E:RtemsReqPerf:D:0.000178950",
+        "M:B:RtemsReqPerf",
+        "M:V:DirtyCache",
+        "M:N:100",
+        "M:S:100:0.000002125",
+        "M:MI:0.000002125",
+        "M:P1:0.000002125",
+        "M:Q1:0.000002125",
+        "M:Q2:0.000002125",
+        "M:Q3:0.000002125",
+        "M:P99:0.000002125",
+        "M:MX:0.000002125",
+        "M:MAD:0.000000000",
+        "M:D:0.000212481",
+        "M:E:RtemsReqPerf:D:0.005231937",
+        "M:B:RtemsReqPerf",
+        "M:V:Load/1",
+        "M:N:100",
+        "M:S:100:0.000001062",
+        "M:MI:0.000001062",
+        "M:P1:0.000001062",
+        "M:Q1:0.000001062",
+        "M:Q2:0.000001062",
+        "M:Q3:0.000001062",
+        "M:P99:0.000001062",
+        "M:MX:0.000001062",
+        "M:MAD:0.000000000",
+        "M:D:0.000106241",
+        "M:E:RtemsReqPerf:D:0.005695012",
+        "E:ScoreCpuValPerf:N:1:F:0:D:3.654440",
+        "Z:TestsuitesPerformanceNoClock0:C:7:N:4039:F:0:D:56.967524",
+        "Y:ReportHash:SHA256:D7Ra09o36-RifrdQ5T9G7Flk31HmQL9BYw6Cq4HROA8=",
+        "",
+        "*** END OF TEST TestsuitesPerformanceNoClock0 ***",
+        "",
+        "  ",
+        "  CPU 0:  Program exited normally."
+      ],
+      "test-suite": {
+        "bsp": "gr712rc",
+        "build-label": "sparc/gr712rc/uni/6/qual-only",
+        "compiler": "13.2.0",
+        "duration": 56.967524,
+        "failed-steps-count": 0,
+        "line-begin": 89,
+        "line-bsp": 93,
+        "line-build-label": 94,
+        "line-compiler": 91,
+        "line-duration": 2440,
+        "line-end": 2440,
+        "line-failed-steps-count": 2440,
+        "line-platform": 90,
+        "line-report-hash": 2441,
+        "line-rtems-debug": 96,
+        "line-rtems-multiprocessing": 97,
+        "line-rtems-posix-api": 98,
+        "line-rtems-profiling": 99,
+        "line-rtems-smp": 100,
+        "line-step-count": 2440,
+        "line-target-hash": 95,
+        "line-version": 92,
+        "name": "TestsuitesPerformanceNoClock0",
+        "platform": "RTEMS",
+        "report-hash": "D7Ra09o36-RifrdQ5T9G7Flk31HmQL9BYw6Cq4HROA8=",
+        "report-hash-calculated": "D7Ra09o36-RifrdQ5T9G7Flk31HmQL9BYw6Cq4HROA8=",
+        "rtems-debug": false,
+        "rtems-multiprocessing": false,
+        "rtems-posix-api": false,
+        "rtems-profiling": false,
+        "rtems-smp": false,
+        "step-count": 4039,
+        "target-hash": "cpI09Ju6orF2eoJcmJi4igeIarypsRNwUxTrZSs9LMg=",
+        "test-cases": [
+          {
+            "duration": 3.65444,
+            "failed-steps-count": 0,
+            "line-begin": 101,
+            "line-duration": 222,
+            "line-end": 222,
+            "line-failed-steps-count": 222,
+            "line-step-count": 222,
+            "name": "ScoreCpuValPerf",
+            "runtime-measurements": [
+              {
+                "duration-sum": 2.7697e-05,
+                "duration-total": 0.007165362,
+                "line-begin": 102,
+                "line-end": 116,
+                "mad": 0.0,
+                "max": 4.75e-07,
+                "min": 2.75e-07,
+                "name": "RtemsReqPerf",
+                "p1": 2.75e-07,
+                "p99": 4.75e-07,
+                "q1": 2.75e-07,
+                "q2": 2.75e-07,
+                "q3": 2.75e-07,
+                "sample-count": 100,
+                "samples": [
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  4.75e-07
+                ],
+                "variant": "FullCache"
+              },
+              {
+                "duration-sum": 2.7497e-05,
+                "duration-total": 0.00017895,
+                "line-begin": 117,
+                "line-end": 130,
+                "mad": 0.0,
+                "max": 2.75e-07,
+                "min": 2.75e-07,
+                "name": "RtemsReqPerf",
+                "p1": 2.75e-07,
+                "p99": 2.75e-07,
+                "q1": 2.75e-07,
+                "q2": 2.75e-07,
+                "q3": 2.75e-07,
+                "sample-count": 100,
+                "samples": [
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07,
+                  2.75e-07
+                ],
+                "variant": "HotCache"
+              },
+              {
+                "duration-sum": 0.000212481,
+                "duration-total": 0.005231937,
+                "line-begin": 131,
+                "line-end": 144,
+                "mad": 0.0,
+                "max": 2.125e-06,
+                "min": 2.125e-06,
+                "name": "RtemsReqPerf",
+                "p1": 2.125e-06,
+                "p99": 2.125e-06,
+                "q1": 2.125e-06,
+                "q2": 2.125e-06,
+                "q3": 2.125e-06,
+                "sample-count": 100,
+                "samples": [
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06,
+                  2.125e-06
+                ],
+                "variant": "DirtyCache"
+              },
+              {
+                "duration-sum": 0.000106241,
+                "duration-total": 0.005695012,
+                "line-begin": 145,
+                "line-end": 158,
+                "mad": 0.0,
+                "max": 1.062e-06,
+                "min": 1.062e-06,
+                "name": "RtemsReqPerf",
+                "p1": 1.062e-06,
+                "p99": 1.062e-06,
+                "q1": 1.062e-06,
+                "q2": 1.062e-06,
+                "q3": 1.062e-06,
+                "sample-count": 100,
+                "samples": [
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06,
+                  1.062e-06
+                ],
+                "variant": "Load/1"
+              }
+            ]
+          }
+        ],
+        "version": "6.0.0.8c9a5d0e1eae450dd28344be9390936a4573740d"
+      }
+    }
+  ],
+  "start-time": "2023-07-11T09:47:29.050266"
+}
diff --git a/rtemsspec/tests/test_packagebuild.py b/rtemsspec/tests/test_packagebuild.py
index 5ad614d8..eff36428 100644
--- a/rtemsspec/tests/test_packagebuild.py
+++ b/rtemsspec/tests/test_packagebuild.py
@@ -41,7 +41,9 @@ from rtemsspec.packagebuild import BuildItem, BuildItemMapper, \
     build_item_input, PackageBuildDirector
 from rtemsspec.packagebuildfactory import create_build_item_factory
 from rtemsspec.rtems import RTEMSItemCache
+import rtemsspec.packagemanual
 from rtemsspec.specverify import verify
+from rtemsspec.sphinxcontent import make_label
 import rtemsspec.sphinxbuilder
 import rtemsspec.testrunner
 from rtemsspec.testrunner import Executable, Report, TestRunner
@@ -150,14 +152,43 @@ def _sphinx_builder_run_command(args, cwd=None, stdout=None):
     if "pkg-config" in args:
         stdout.append(" ".join(args))
         return 0
-    if args[0].endswith("verify"):
-        stdout.append("verify")
+    if args[0].endswith("verify_package.py"):
+        stdout.append("verify_package.py")
         return 0
     return 1
 
 
+def _package_manual_generate(content, sections_by_uid, root, table_pivots,
+                             mapper):
+    content.add([root.uid, mapper.item.uid] + table_pivots +
+                list(sections_by_uid.keys()))
+
+
+def _clear_benchmark_variants(ctx: ItemGetValueContext) -> str:
+    ctx.item["benchmark-variants"] = [{
+        "description": "Description",
+        "build-label": "foobar",
+        "name": "Name",
+        "test-log-uid": "../build/disabled"
+    }]
+    return "clear benchmark variants"
+
+
+def _clear_copyrights_by_license(ctx: ItemGetValueContext) -> str:
+    ctx.item.cache["/qdp/source/a"]["copyrights-by-license"] = {}
+    return "clear copyrights by license"
+
+
+def _format_path(path: Path) -> str:
+    path_2 = str(path)
+    for char in "/-_.":
+        path_2 = path_2.replace(char, f"{char}\u200b")
+    return path_2
+
+
 def test_packagebuild(caplog, tmpdir, monkeypatch):
     tmp_dir = Path(tmpdir)
+    tmp_dir_len = len(str(tmp_dir))
     item_cache = _create_item_cache(tmp_dir, Path("spec-packagebuild"))
 
     caplog.set_level(logging.WARN)
@@ -196,7 +227,11 @@ def test_packagebuild(caplog, tmpdir, monkeypatch):
     assert [item.uid for item in related_items] == ["/rtems/test-case"]
     related_types = rtems_item_cache.get_related_types_by_prefix("requirement")
     assert related_types == [
-        "requirement/functional/function", "requirement/non-functional/design"
+        "requirement/functional/function", "requirement/non-functional/design",
+        "requirement/non-functional/design-target",
+        "requirement/non-functional/interface-requirement",
+        "requirement/non-functional/performance-runtime",
+        "requirement/non-functional/quality"
     ]
     related_items = rtems_item_cache.get_related_interfaces()
     assert [item.uid for item in related_items] == [
@@ -204,11 +239,15 @@ def test_packagebuild(caplog, tmpdir, monkeypatch):
         "/rtems/if"
     ]
     related_items = rtems_item_cache.get_related_requirements()
-    assert [item.uid for item in related_items] == ["/req/root", "/rtems/req"]
+    assert [item.uid for item in related_items] == [
+        "/req/api", "/req/root", "/rtems/req", "/rtems/req/mem-basic",
+        "/rtems/req/perf", "/rtems/target-a"
+    ]
     related_items = rtems_item_cache.get_related_interfaces_and_requirements()
     assert [item.uid for item in related_items] == [
-        "/req/root", "/rtems/domain", "/rtems/group", "/rtems/group-acfg",
-        "/rtems/header", "/rtems/if", "/rtems/req"
+        "/req/api", "/req/root", "/rtems/domain", "/rtems/group",
+        "/rtems/group-acfg", "/rtems/header", "/rtems/if", "/rtems/req",
+        "/rtems/req/mem-basic", "/rtems/req/perf", "/rtems/target-a"
     ]
 
     director.build_package(None, ["/qdp/steps/a"])
@@ -236,6 +275,9 @@ def test_packagebuild(caplog, tmpdir, monkeypatch):
     assert c["blub"] == "bar"
     assert c.substitute(c.item["blub"], c.item) == "bar"
     assert c.substitute("${/qdp/variant:/spec}") == "spec:/qdp/variant"
+    assert c.substitute(
+        "${/qdp/issue/rtems/2189:/name}"
+    ) == "`RTEMS Ticket #2189 <https://devel.rtems.org/ticket/2189>`__"
     assert c.variant.uid == "/qdp/variant"
     variant_config = c.variant["config"]
     c.variant["config"] = ""
@@ -659,3 +701,401 @@ Terms, definitions and abbreviated terms
     doc_2.add_component_action("foobar", action)
     director.build_package(None, None)
     assert action_run == 1
+
+    # Test SRelDBuilder
+    variant["enabled"] = ["ddf-sreld"]
+    director["/qdp/source/doc-ddf-sreld"].load()
+    director.build_package(None, None)
+    ddf_sreld_build = Path(director["/qdp/build/doc-ddf-sreld"].directory)
+    ddf_sreld_index = ddf_sreld_build / "source" / "index.rst"
+    with open(ddf_sreld_index, "r", encoding="utf-8") as src:
+        assert src.read() == f""".. SPDX-License-Identifier: CC-BY-SA-4.0
+
+.. Copyright (C) 2023 embedded brains GmbH & Co. KG
+
+Description 2.
+
+.. _NewIssues:
+
+New issues
+----------
+
+When the QDP of this package version was produced, there were the following new issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+---------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                 |
+    +==============+===============================================+=========================================================+
+    | RTEMS Ticket | `2548 <https://devel.rtems.org/ticket/2548>`_ | Problematic integer conversion in rtems_clock_get_tod() |
+    +--------------+-----------------------------------------------+---------------------------------------------------------+
+
+.. _OpenIssues:
+
+Open issues
+-----------
+
+When the QDP of this package version was produced, there were the following open issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                    |
+    +==============+===============================================+============================================================+
+    | RTEMS Ticket | `2365 <https://devel.rtems.org/ticket/2365>`_ | Task pre-emption disable is broken due to pseudo ISR tasks |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+
+.. _ClosedIssues:
+
+Closed issues
+-------------
+
+The following issues were closed for this package version.
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                              |
+    +==============+===============================================+======================================================+
+    | RTEMS Ticket | `2189 <https://devel.rtems.org/ticket/2189>`_ | Insufficient documentation for rtems_clock_get_tod() |
+    +--------------+-----------------------------------------------+------------------------------------------------------+
+"""
+
+    # Test PackageManualBuilder
+    variant["enabled"] = ["package-manual"]
+    director["/qdp/source/archive"].load()
+    director["/qdp/source/doc-package-manual"].load()
+    director["/qdp/test-logs/membench-2"].load()
+    pm = director["/qdp/steps/doc-package-manual"]
+    pm.mapper.add_get_value(f"{pm.item.type}:/clear-benchmark-variants",
+                            _clear_benchmark_variants)
+    pm.mapper.add_get_value(f"{pm.item.type}:/clear-copyrights-by-license",
+                            _clear_copyrights_by_license)
+    monkeypatch.setattr(rtemsspec.packagemanual, "run_command",
+                        _sphinx_builder_run_command)
+    monkeypatch.setattr(rtemsspec.packagemanual, "generate",
+                        _package_manual_generate)
+    director.build_package(None, None)
+    monkeypatch.undo()
+    pm_build = Path(director["/qdp/build/doc-package-manual"].directory)
+    pm_index = pm_build / "source" / "index.rst"
+    with open(pm_index, "r", encoding="utf-8") as src:
+        assert src.read() == f""".. SPDX-License-Identifier: CC-BY-SA-4.0
+
+.. Copyright (C) 2023 embedded brains GmbH & Co. KG
+
+archive.tar.xz
+6\u200b6\u200b3\u200b0\u200b4\u200b9\u200ba\u200b2\u200b0\u200bd\u200bf\u200be\u200ba\u200b6\u200bb\u200b8\u200bd\u200ba\u200b2\u200b8\u200bb\u200b2\u200be\u200bb\u200b9\u200b0\u200be\u200bd\u200bd\u200bd\u200b1\u200b0\u200bc\u200bc\u200bf\u200b2\u200b8\u200be\u200bf\u200b2\u200b5\u200b1\u200b9\u200b5\u200b6\u200b3\u200b3\u200b1\u200b0\u200bb\u200b9\u200bb\u200bd\u200be\u200b2\u200b5\u200bb\u200b7\u200b2\u200b6\u200b8\u200b4\u200b4\u200b4\u200b0\u200b1\u200b4\u200bc\u200b4\u200b8\u200bc\u200b4\u200b3\u200b8\u200b4\u200be\u200be\u200b5\u200bc\u200b5\u200ba\u200b5\u200b4\u200be\u200b7\u200b8\u200b3\u200b0\u200be\u200b4\u200b5\u200bf\u200bc\u200bd\u200b8\u200b7\u200bd\u200bf\u200b7\u200b9\u200b1\u200b0\u200ba\u200b7\u200bf\u200bd\u200ba\u200b7\u200b7\u200bb\u200b6\u200b8\u200bc\u200b2\u200be\u200bf\u200bd\u200bd\u200b7\u200b5\u200bf\u200b8\u200bd\u200be\u200b2\u200b5\u200be\u200b8
+.. code-block:: none
+
+    $ pkg-config --variable=ABI_FLAGS {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+    pkg-config --variable=ABI_FLAGS {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+
+    $ pkg-config --cflags {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+    pkg-config --cflags {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+
+    $ pkg-config --libs {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+    pkg-config --libs {tmp_dir}/pkg/lib/pkgconfig/sparc-rtems6-gr712rc-qual-only.pc
+verify_package.py
+.. code-block:: none
+
+    $ cd {tmp_dir}
+    $ ./verify_package.py --help
+    verify_package.py
+b​6​3​5​4​f​6​4​a​1​a​2​6​1​a​2​e​7​1​0​1​5​a​b​5​1​f​c​5​d​3​c​a​8​7​6​3​0​5​c​b​a​2​7​3​3​5​5​7​e​b​f​e​3​e​2​c​0​a​0​9​5​1​e​2​c​6​1​e​7​6​3​d​8​a​9​e​d​d​b​b​4​d​4​1​e​5​6​c​e​f​3​d​d​f​8​a​8​0​2​3​e​a​7​e​f​7​a​a​f​e​9​9​6​b​b​b​1​f​a​4​5​4​7​3​3​5​0
+.. code-block:: none
+
+    ​example
+4
+Name 1
+    Description 1
+
+Name 2
+    Description 2
+
+Name 3
+    Description 3
+/rtems/req/mem-basic
+/rtems/req/mem-basic
+/rtems/req/mem-smp-1
+/rtems/val/mem-basic
+123
++0
+.. raw:: latex
+
+    \\begin{{scriptsize}}
+
+.. table::
+    :class: longtable
+    :widths: 35,20,9,9,9,9,9
+
+    +---------------+---------+-------+---------+-------+------+---------+
+    | Specification | Variant | .text | .rodata | .data | .bss | .noinit |
+    +===============+=========+=======+=========+=======+======+=========+
+    +---------------+---------+-------+---------+-------+------+---------+
+
+.. raw:: latex
+
+    \\end{{scriptsize}}
+.. raw:: latex
+
+    \\begin{{scriptsize}}
+
+.. table::
+    :class: longtable
+    :widths: 31,14,19,12,12,12
+
+    +----------------------+-------------{'-' * tmp_dir_len}------------------------------------------------------------------------------------------+---------+----------+-------------+----------+
+    | Specification        | Environment {' ' * tmp_dir_len}                                                                                          | Variant | Min [μs] | Median [μs] | Max [μs] |
+    +======================+============={'=' * tmp_dir_len}==========================================================================================+=========+==========+=============+==========+
+    | spec:/rtems/req/perf | `HotCache <{tmp_dir}/pkg/doc/ts/srs/html/requirements.html#spec-req-perf-runtime-environment-hot-cache>`__     | Name 1  | 0.275    | 0.275       | 0.275    |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 2  | +0 %     | +0 %        | +0 %     |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 3  | ?        | ?           | ?        |
+    +                      +-------------{'-' * tmp_dir_len}------------------------------------------------------------------------------------------+---------+----------+-------------+----------+
+    |                      | `FullCache <{tmp_dir}/pkg/doc/ts/srs/html/requirements.html#spec-req-perf-runtime-environment-full-cache>`__   | Name 1  | 0.275    | 0.275       | 0.475    |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 2  | +0 %     | +0 %        | +0 %     |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 3  | ?        | ?           | ?        |
+    +                      +-------------{'-' * tmp_dir_len}------------------------------------------------------------------------------------------+---------+----------+-------------+----------+
+    |                      | `DirtyCache <{tmp_dir}/pkg/doc/ts/srs/html/requirements.html#spec-req-perf-runtime-environment-dirty-cache>`__ | Name 1  | 2.125    | 2.125       | 2.125    |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 2  | +0 %     | +0 %        | +0 %     |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 3  | ?        | ?           | ?        |
+    +                      +-------------{'-' * tmp_dir_len}------------------------------------------------------------------------------------------+---------+----------+-------------+----------+
+    |                      | `Load/1 <{tmp_dir}/pkg/doc/ts/srs/html/requirements.html#spec-req-perf-runtime-environment-load>`__            | Name 1  | 1.062    | 1.062       | 1.062    |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 2  | +0 %     | +0 %        | +0 %     |
+    +                      +             {' ' * tmp_dir_len}                                                                                          +---------+----------+-------------+----------+
+    |                      |             {' ' * tmp_dir_len}                                                                                          | Name 3  | ?        | ?           | ?        |
+    +----------------------+-------------{'-' * tmp_dir_len}------------------------------------------------------------------------------------------+---------+----------+-------------+----------+
+
+.. raw:: latex
+
+    \\end{{scriptsize}}
+clear benchmark variants
+.. raw:: latex
+
+    \\begin{{scriptsize}}
+
+.. table::
+    :class: longtable
+    :widths: 35,20,9,9,9,9,9
+
+    +---------------+---------+-------+---------+-------+------+---------+
+    | Specification | Variant | .text | .rodata | .data | .bss | .noinit |
+    +===============+=========+=======+=========+=======+======+=========+
+    +---------------+---------+-------+---------+-------+------+---------+
+
+.. raw:: latex
+
+    \\end{{scriptsize}}
+There is no performance variants table available.
+.. _GitRepositoryBuildSrcB:
+
+Git Repository: build/src/b
+---------------------------
+
+B
+
+The ``qdp`` branch with
+commit ``52f06822b8921ad825cb593b792eab7640e26cde``
+was used to build the QDP.  This branch is checked out after unpacking the
+archive.  It is based on
+commit `bcef89f2360b97005e490c92fe624ab9dec789e6 <https://git.rtems.org/rtems/commit/?id=bcef89f2360b97005e490c92fe624ab9dec789e6>`_
+of the ``master`` branch of the ``origin`` remote repository.
+.. _Name:
+
+Name
+----
+
+* identity
+.. _NameTargetA:
+
+Name Target A
+-------------
+
+Brief target A.
+
+Description target A.
+
+.. _Name2:
+
+Name 2
+------
+
+Description 2.
+
+.. _Name2NewIssues:
+
+New issues
+^^^^^^^^^^
+
+When the QDP of this package version was produced, there were the following new issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+---------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                 |
+    +==============+===============================================+=========================================================+
+    | RTEMS Ticket | `2548 <https://devel.rtems.org/ticket/2548>`_ | Problematic integer conversion in rtems_clock_get_tod() |
+    +--------------+-----------------------------------------------+---------------------------------------------------------+
+
+.. _Name2OpenIssues:
+
+Open issues
+^^^^^^^^^^^
+
+When the QDP of this package version was produced, there were the following open issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                    |
+    +==============+===============================================+============================================================+
+    | RTEMS Ticket | `2365 <https://devel.rtems.org/ticket/2365>`_ | Task pre-emption disable is broken due to pseudo ISR tasks |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+
+.. _Name2ClosedIssues:
+
+Closed issues
+^^^^^^^^^^^^^
+
+The following issues were closed for this package version.
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                              |
+    +==============+===============================================+======================================================+
+    | RTEMS Ticket | `2189 <https://devel.rtems.org/ticket/2189>`_ | Insufficient documentation for rtems_clock_get_tod() |
+    +--------------+-----------------------------------------------+------------------------------------------------------+
+
+.. _Name1:
+
+Name 1
+------
+
+Description 1.
+
+.. _Name1NewIssues:
+
+New issues
+^^^^^^^^^^
+
+When the QDP of this package version was produced, there were the following new issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                    |
+    +==============+===============================================+============================================================+
+    | RTEMS Ticket | `2189 <https://devel.rtems.org/ticket/2189>`_ | Insufficient documentation for rtems_clock_get_tod()       |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | RTEMS Ticket | `2365 <https://devel.rtems.org/ticket/2365>`_ | Task pre-emption disable is broken due to pseudo ISR tasks |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+
+.. _Name1OpenIssues:
+
+Open issues
+^^^^^^^^^^^
+
+When the QDP of this package version was produced,
+there were no open issues associated.
+
+.. _Name1ClosedIssues:
+
+Closed issues
+^^^^^^^^^^^^^
+
+When the QDP of this package version was produced,
+there were no closed issues associated.
+.. _OpenIssues:
+
+Open issues
+-----------
+
+When the QDP of this package version was produced, there were the following open issues associated:
+
+.. table::
+    :class: longtable
+    :widths: 27,14,59
+
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | Database     | Identifier                                    | Subject                                                    |
+    +==============+===============================================+============================================================+
+    | RTEMS Ticket | `2365 <https://devel.rtems.org/ticket/2365>`_ | Task pre-emption disable is broken due to pseudo ISR tasks |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+    | RTEMS Ticket | `2548 <https://devel.rtems.org/ticket/2548>`_ | Problematic integer conversion in rtems_clock_get_tod()    |
+    +--------------+-----------------------------------------------+------------------------------------------------------------+
+All directories and file paths in this section are
+relative to :file:`{_format_path(tmp_dir / 'pkg')}`.
+
+.. _Directory:
+
+Directory - ..
+--------------
+
+.. _Directory FileDirATxt:
+
+File - dir/a.txt
+^^^^^^^^^^^^^^^^
+
+The license file
+:file:`.​.​/​dir/​a.​txt`
+is applicable to this directory or parts of the directory:
+
+.. code-block:: none
+
+    ​A
+
+.. _BSD2ClauseCopyrights:
+
+BSD-2-Clause copyrights
+-----------------------
+
+| © 2023 Alice
+
+.. code-block:: none
+
+    ​Redistribution and use in source and binary forms, with or without
+    ​modification, are permitted provided that the following conditions
+    ​are met:
+    ​1. Redistributions of source code must retain the above copyright
+    ​   notice, this list of conditions and the following disclaimer.
+    ​2. Redistributions in binary form must reproduce the above copyright
+    ​   notice, this list of conditions and the following disclaimer in the
+    ​   documentation and/or other materials provided with the distribution.
+    ​
+    ​THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    ​AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    ​IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ​ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+    ​LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+    ​CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+    ​SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+    ​INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+    ​CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ​ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+    ​POSSIBILITY OF SUCH DAMAGE.
+clear copyrights by license
+All directories and file paths in this section are
+relative to :file:`{_format_path(tmp_dir / 'pkg')}`.
+"""
diff --git a/spec-qdp/spec/qdp-doc-ddf-sreld.yml b/spec-qdp/spec/qdp-doc-ddf-sreld.yml
new file mode 100644
index 00000000..fee636e6
--- /dev/null
+++ b/spec-qdp/spec/qdp-doc-ddf-sreld.yml
@@ -0,0 +1,22 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: document-type
+  spec-value: ddf-sreld
+  uid: qdp-sphinx-build
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes: {}
+    description: |
+      This set of attributes specifies a Software Release Document (SRelD).
+    mandatory-attributes: all
+spec-name: Software Release Document (SRelD) Item Type
+spec-type: qdp-doc-ddf-sreld
+type: spec
diff --git a/spec-qdp/spec/qdp-git-hash.yml b/spec-qdp/spec/qdp-git-hash.yml
new file mode 100644
index 00000000..c24e1608
--- /dev/null
+++ b/spec-qdp/spec/qdp-git-hash.yml
@@ -0,0 +1,18 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+spec-description: null
+spec-example: null
+spec-info:
+  str:
+    assert:
+    - re: ^[0-9a-f]{5,40}$
+    description: |
+      It shall be a Git hash.
+spec-name: Git Hash
+spec-type: qdp-git-hash
+type: spec
diff --git a/spec-qdp/spec/qdp-input-generic-role.yml b/spec-qdp/spec/qdp-input-generic-role.yml
index a75bc7ee..4db9da04 100644
--- a/spec-qdp/spec/qdp-input-generic-role.yml
+++ b/spec-qdp/spec/qdp-input-generic-role.yml
@@ -33,6 +33,10 @@ links:
   spec-key: name
   spec-value: member
   uid: qdp-input-role
+- role: spec-refinement
+  spec-key: name
+  spec-value: package-changes
+  uid: qdp-input-role
 - role: spec-refinement
   spec-key: name
   spec-value: runner
diff --git a/spec-qdp/spec/qdp-issue-database.yml b/spec-qdp/spec/qdp-issue-database.yml
new file mode 100644
index 00000000..531d043b
--- /dev/null
+++ b/spec-qdp/spec/qdp-issue-database.yml
@@ -0,0 +1,34 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: qdp-type
+  spec-value: issue-database
+  uid: qdp-root
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      name:
+        description: |
+          It shall be the name of the issue database.
+        spec-type: str
+      format-identifier:
+        description: |
+          It shall be the format of an issue identifier in a document.
+        spec-type: str
+      url:
+        description: |
+          It shall be URL to issues of the database.
+        spec-type: str
+    description: |
+      This set of attributes specifies an issue database.
+    mandatory-attributes: all
+spec-name: Issue Database Item Type
+spec-type: qdp-issue-database
+type: spec
diff --git a/spec-qdp/spec/qdp-issue-member-role.yml b/spec-qdp/spec/qdp-issue-member-role.yml
new file mode 100644
index 00000000..7c710460
--- /dev/null
+++ b/spec-qdp/spec/qdp-issue-member-role.yml
@@ -0,0 +1,23 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: role
+  spec-value: issue-member
+  uid: link
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes: {}
+    description: |
+      It defines the issue membership role of links and is used to associate an
+      issue with its database.
+    mandatory-attributes: all
+spec-name: Issue Member Link Role
+spec-type: qdp-issue-member-role
+type: spec
diff --git a/spec-qdp/spec/qdp-issue-role.yml b/spec-qdp/spec/qdp-issue-role.yml
new file mode 100644
index 00000000..28a99ce6
--- /dev/null
+++ b/spec-qdp/spec/qdp-issue-role.yml
@@ -0,0 +1,27 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022, 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: role
+  spec-value: issue
+  uid: link
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      status:
+        description: |
+          If shall be the status of the issue with respect to the package.
+        spec-type: qdp-issue-status
+    description: |
+      It defines the issue role of links and is used to associate issues with a
+      packages status.
+    mandatory-attributes: all
+spec-name: Issue Link Role
+spec-type: qdp-issue-role
+type: spec
diff --git a/spec-qdp/spec/qdp-issue-status.yml b/spec-qdp/spec/qdp-issue-status.yml
new file mode 100644
index 00000000..0c07d9a9
--- /dev/null
+++ b/spec-qdp/spec/qdp-issue-status.yml
@@ -0,0 +1,20 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+spec-description: null
+spec-example: null
+spec-info:
+  str:
+    assert:
+      in:
+      - closed
+      - open
+    description: |
+      It shall be an issue status.
+spec-name: Issue Status
+spec-type: qdp-issue-status
+type: spec
diff --git a/spec-qdp/spec/qdp-issue.yml b/spec-qdp/spec/qdp-issue.yml
new file mode 100644
index 00000000..a95f6261
--- /dev/null
+++ b/spec-qdp/spec/qdp-issue.yml
@@ -0,0 +1,50 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2021 EDISOFT
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: qdp-type
+  spec-value: issue
+  uid: qdp-root
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      created:
+        description: |
+          It shall be time when the issue was created.
+        spec-type: str
+      identifier:
+        description: |
+          It shall be identifier of the issue in relation to its database.
+        spec-type: str
+      labels:
+        description: |
+          It shall be the list of labels of the issue.
+        spec-type: list-str
+      milestone:
+        description: |
+          If the value is present, then it shall be the milestone the issue.
+        spec-type: optional-str
+      status:
+        description: |
+          It shall be the status of the issue at the update time.
+        spec-type: str
+      subject:
+        description: |
+          It shall be the subject of the issue.
+        spec-type: str
+      updated:
+        description: |
+          It shall be time of the last known issue update.
+        spec-type: str
+    description: |
+      This set of attributes specifies an issue.
+    mandatory-attributes: all
+spec-name: Issue Item Type
+spec-type: qdp-issue
+type: spec
diff --git a/spec-qdp/spec/qdp-optional-git-hash.yml b/spec-qdp/spec/qdp-optional-git-hash.yml
new file mode 100644
index 00000000..65b16999
--- /dev/null
+++ b/spec-qdp/spec/qdp-optional-git-hash.yml
@@ -0,0 +1,19 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+spec-description: null
+spec-example: null
+spec-info:
+  none: null
+  str:
+    assert:
+    - re: ^[0-9a-f]{5,40}$
+    description: |
+      It shall be a Git hash.
+spec-name: Optional Git Hash
+spec-type: qdp-optional-git-hash
+type: spec
diff --git a/spec-qdp/spec/qdp-package-change-list.yml b/spec-qdp/spec/qdp-package-change-list.yml
new file mode 100644
index 00000000..67b868a4
--- /dev/null
+++ b/spec-qdp/spec/qdp-package-change-list.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+spec-description: null
+spec-example: null
+spec-info:
+  list:
+    description: null
+    spec-type: qdp-package-change
+spec-name: Package Change List
+spec-type: qdp-package-change-list
+type: spec
diff --git a/spec-qdp/spec/qdp-package-change.yml b/spec-qdp/spec/qdp-package-change.yml
new file mode 100644
index 00000000..edfc2a71
--- /dev/null
+++ b/spec-qdp/spec/qdp-package-change.yml
@@ -0,0 +1,30 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      description:
+        description: |
+          It shall be the package change description.
+        spec-type: str
+      name:
+        description: |
+          It shall be the package change name.
+        spec-type: str
+      package-status:
+        description: |
+          It shall be package status UID.
+        spec-type: uid
+    description: |
+      This set of attributes specifies a package change.
+    mandatory-attributes: all
+spec-name: Package Change Release
+spec-type: qdp-package-change
+type: spec
diff --git a/spec-qdp/spec/qdp-package-changes.yml b/spec-qdp/spec/qdp-package-changes.yml
new file mode 100644
index 00000000..72d95c2b
--- /dev/null
+++ b/spec-qdp/spec/qdp-package-changes.yml
@@ -0,0 +1,26 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: qdp-type
+  spec-value: package-changes
+  uid: qdp-root
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      change-list:
+        description: |
+          It shall be the package change list.
+        spec-type: qdp-package-change-list
+    description: |
+      This set of attributes specifies a list of package changes.
+    mandatory-attributes: all
+spec-name: Package Changes Item Type
+spec-type: qdp-package-changes
+type: spec
diff --git a/spec-qdp/spec/qdp-package-manual.yml b/spec-qdp/spec/qdp-package-manual.yml
new file mode 100644
index 00000000..de9e7a76
--- /dev/null
+++ b/spec-qdp/spec/qdp-package-manual.yml
@@ -0,0 +1,30 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: document-type
+  spec-value: package-manual
+  uid: qdp-sphinx-build
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes:
+      benchmark-variants:
+        description: |
+          It shall be the benchmark variant list.
+        spec-type: any
+      memory-benchmark-build-label:
+        description: |
+          It shall be the build label to get the memory benchmarks.
+        spec-type: str
+    description: |
+      This set of attributes specifies a package manual.
+    mandatory-attributes: all
+spec-name: Package Manual Item Type
+spec-type: qdp-package-manual
+type: spec
diff --git a/spec-qdp/spec/qdp-package-status.yml b/spec-qdp/spec/qdp-package-status.yml
new file mode 100644
index 00000000..b9529f92
--- /dev/null
+++ b/spec-qdp/spec/qdp-package-status.yml
@@ -0,0 +1,26 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: qdp-type
+  spec-value: package-status
+  uid: qdp-root
+spec-description: |
+  Items of this type shall have the following links:
+
+  * There shall be links to ${qdp-issue:/spec-name} items
+    with the ${qdp-issue-role:/spec-name}.
+spec-example: null
+spec-info:
+  dict:
+    attributes: {}
+    description: |
+      This set of attributes specifies a package status.
+    mandatory-attributes: all
+spec-name: Package Status Item Type
+spec-type: qdp-package-status
+type: spec



More information about the vc mailing list