Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d27eadd
🧪 Conformance runners compare floats by their bits: -0.0 is not 0.0, …
chrisjsewell Oct 27, 2026
e0bf0eb
👌 needextend's computed-field warning names what computes the field: …
chrisjsewell Oct 27, 2026
ebdcb40
🧪 derive corpus: links-include-parts is no longer python_only
chrisjsewell Oct 27, 2026
6b4f182
🧪 derive corpus: the cases phase 2 measured but never wrote
chrisjsewell Oct 27, 2026
175b227
📚 Derived fields: start a list roll-up one rung up, and read the chai…
chrisjsewell Oct 27, 2026
a9e627e
✨ Derive kinds `any` and `all` take `empty`: the value over no candidate
chrisjsewell Oct 27, 2026
3f70b34
✨ Derive kind `copy` takes `where` beside `over` or `join`
chrisjsewell Oct 27, 2026
8ea6a87
📚 Derive review nits: the corpus header states the float rule, the ru…
chrisjsewell Oct 27, 2026
2f32c2a
✨ Summary link types: `summary = true` on a link type's entry
chrisjsewell Oct 27, 2026
b02b02f
✨ Derive kinds `copy` and `collect` on a link type: a chain's far end…
chrisjsewell Oct 27, 2026
829dc91
🧪 The schema snapshot shows a link type's summary flag
chrisjsewell Oct 27, 2026
8f92ef3
🔧 ruff format test_derive_link_paths.py
chrisjsewell Oct 28, 2026
6a7f585
👌 Summary links, review round 1: chains over a union, dead links wher…
chrisjsewell Oct 28, 2026
118e7ac
🧪 derive corpus: link-kinds-refusals says which over the lifted refus…
chrisjsewell Oct 28, 2026
4a1180f
🔀 Merge master into the summary link types branch
chrisjsewell Oct 30, 2026
1799efa
🐛 Incremental builds: a collect on a link type re-writes every need-r…
chrisjsewell Oct 30, 2026
f0db20a
🧪 Summary link types on need types: a back_links count, c.is_a in a w…
chrisjsewell Oct 30, 2026
02de261
🔧 ENV_DATA_VERSION is 17: copy and collect on a link type compute, su…
chrisjsewell Oct 30, 2026
00fd5d7
🧪 derive corpus: link-path-where-is-a, a copy's and a collect's where…
chrisjsewell Oct 30, 2026
474f153
📚 Changelog: a collect on a link type and incremental builds
chrisjsewell Oct 30, 2026
aa41bee
🔧 ruff format test_incremental_rewrite.py
chrisjsewell Oct 30, 2026
2abfab4
🧪 The known keys of a link type's entry include summary
chrisjsewell Oct 30, 2026
7c2185d
📚 A summary's docs name a copy over a computed link type, and its nee…
chrisjsewell Oct 30, 2026
867a6ad
🔀 Merge master into the summary branch: hidden-need location (#2415);…
chrisjsewell Oct 30, 2026
c1e2322
🔀 Merge master into the summary branch: NeedItemSource (#2419); ENV_D…
chrisjsewell Oct 30, 2026
d68c99b
📚 Summary link types: lead with what they are for, a shortcut across …
chrisjsewell Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/sphinx-needs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ The `ensure_post_process_needs_data` function calls `post_process_needs_data`, w

1. `extend_needs_data` - Apply all `needextend` modifications to need data
2. `resolve_functions` - Resolve dynamic function values (calls functions set as field values), building the back-links between its strata (`build_backlinks`)
3. `check_links` - Check each link's target type against its link type's `target_types` (as the source need's type declares them; `target_types` on `links` is refused where the schema is built while a link type copies into it), assess link conditions, and report dead/broken links between needs (never under a link type a `union` computed on the need, whose links are its members': `LinkSchema.union_on` is the one predicate every such check asks; `has_dead_links` counts every link type). (`resolve_links` bundles back-links, `check_links` and sorting for callers outside the build; `post_process_needs_data` does not call it.)
3. `check_links` - Check each link's target type against its link type's `target_types` (as the source need's type declares them; `target_types` on `links` is refused where the schema is built while a link type copies into it), assess link conditions, and report dead/broken links between needs (never under a link type a `union` computed on the need, whose links are its members', nor under one a `copy` or `collect` computed, whose links are read from other needs' links: `LinkSchema.union_on` and `LinkSchema.path_on` are the predicates every such check asks; `has_dead_links` counts every link type but a `copy`'s or `collect`'s, whose dead links flag the need writing them). (`resolve_links` bundles back-links, `check_links` and sorting for callers outside the build; `post_process_needs_data` does not call it.)
4. `process_constraints` - Process constraints for each need

After this, needs are "sealed" (made immutable) via the `needs-before-sealing` event.
Expand Down
35 changes: 33 additions & 2 deletions packages/sphinx-needs/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,35 @@ Unreleased
Improvements
............

- ✨ A link type derives a chain's far ends as links: ``copy`` of ``id`` and ``collect`` of a link type, over a
link type, declared on a link type (:ref:`needs_derive_link_chain`, :issue:`2370`)

``{ kind = "copy", field = "id", over = "satisfies" }`` on a specification and
``{ kind = "collect", field = "chain", over = "implements" }`` on the rungs below give every need of the chain the
requirements it traces to as links, and each requirement the needs that reach it as back links. Each link is kept
once by its target and part, its condition dropped; a dead link is carried, and reported where it is written.
Such a link type is a summary (``summary = false`` beside the rule is refused), counts toward
``needs.derive_dense``, and is computed with the link types: an ``over`` naming back links, and a ``field`` naming
a value field or back links, are refused at load (``needs.derive_invalid``), and needs reading one another's chain
around a ring are ``needs.derive_cycle``. ``over`` may name a union, read through its members, so a chain climbs
several link types at once (``over = "trace_up"``); a ``collect`` of its own link type over a link type another
kind of rule computes is refused. A dead link carried is flagged (``has_dead_links``) and drawn forbidden only as
the link type it is written in says. A ``collect``, or a ``copy`` over a link type another rule computes, links needs
its need does not name, so in a project with one every change of a need re-writes every need-relevant page on an incremental build (:ref:`incremental_builds`).
On a field, ``copy`` and ``collect`` are unchanged.

- ✨ **Summary link types**: ``summary = true`` on a :ref:`needs_links` entry marks a link type whose links are
shortcuts across the trace rather than steps in it, such as a test result linked straight to the requirements it
covers (:ref:`needs_derive_summary`, :issue:`2370`)

It works as any link type wherever it is named (a filter, a needtable column, a rule's ``over``, a needflow's
``:link_types:``, a schema rule), and a need holds its links and back links as usual; but a :ref:`needflow`
without ``:link_types:`` neither draws it nor walks it from ``:root_id:``, so a diagram does not show every path twice.
The schema of the ``needs.json`` marks it, and its back links, ``"summary": true``, and a ``union`` cannot name it as
a member (``needs.derive_invalid``). It is set on the link type for every need type: a need type's entry giving it
is a ``needs.config`` warning, and in a rule it is no key (``needs.derive_invalid``); ``copy = true`` beside it is a
``needs.config`` warning, and nothing is copied into ``links``. Without it nothing changes.

- ✨ ``c.is_a('req')`` is true for a need whose type is ``req`` or inherits from it (:issue:`2322`)

``type == 'req'`` compares the type's name alone; ``c.is_a('req')`` follows :ref:`inherits <needs_types_fields>`,
Expand Down Expand Up @@ -344,8 +373,10 @@ Bug fixes
its readers finished. Needs from
``needs_external_needs`` are not compared (:issue:`353`). See :ref:`incremental_builds`.

- 🔧 ``ENV_DATA_VERSION`` is 17: the first build after upgrading re-reads every document, which records
the views and need roles each document holds, and where each hidden need is (:issue:`2398`)
- 🔧 ``ENV_DATA_VERSION`` is 19: the first build after upgrading re-reads every document, which records
the views and need roles each document holds and where each hidden need is (:issue:`2398`), stores each need's
source as one class, and computes the
links a ``copy`` or ``collect`` on a link type, refused until now, computes

- 🐛 A need with ``:hide:`` is located as a visible need in the same place is **(changed output)** (:issue:`2398`)

Expand Down
27 changes: 26 additions & 1 deletion packages/sphinx-needs/docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,8 @@ Each configured link can define:
- ``parse_conditions``: If set to ``False``, the ``[condition]`` bracket syntax will not be parsed for this link type.
Default: ``True``. *New in version 8.0.0.*
- ``derive`` (optional): A rule computing the links of every need, which makes the link type :ref:`derived <needs_derive>`:
a table naming the kind ``links``, ``content_links`` or ``union`` (:ref:`needs_derive_union`), and its roles;
a table naming the kind ``links``, ``content_links`` or ``union`` (:ref:`needs_derive_union`),
or ``copy`` or ``collect``, a path through other links (:ref:`needs_derive_link_chain`), and its roles;
with ``derive_by_type`` beside it, of every need of a type ``derive_by_type`` does not list.
A derived link type cannot be set in a need or by a ``needextend``, and takes no ``default`` or ``predicates``.
*New in version 9.0.0.*
Expand Down Expand Up @@ -1183,6 +1184,30 @@ Each configured link can define:
(``suppress_warnings = ["needs.deprecated"]`` silences it, and every other deprecation).
- ``allow_dead_links`` (optional): True/False. If True, dead links are allowed and do not throw a warning.
See :ref:`allow_dead_links` for details. Default: False.
- ``summary`` (optional): True/False. Default: False.
Set it for a link type whose links are shortcuts across the trace rather than steps in it,
such as a test result linked straight to the requirements it covers, three links up
(:ref:`needs_derive_summary` explains when to use it).
Such a link type works as any other wherever it is named:
a :ref:`filter <filter_string>` (``"REQ_1" in covers``), a :ref:`needtable` column, a rule's ``over`` or ``field``,
a :ref:`needflow`'s ``:link_types:``, a :ref:`schema rule <network_validation>`;
and a need holds its links and back links (``<name>_back``) and shows them, as usual.
The views that take every link type leave it out:
a :ref:`needflow` without ``:link_types:`` neither draws it nor walks it from ``:root_id:``.
The schema of the :ref:`needs.json <needs_builder_format>` marks it, and its back links, ``"summary": true``,
so that a tool reading the file can leave it out too.
A :ref:`union <needs_derive_union>` cannot name it as a member (``needs.derive_invalid``).
A link type a ``copy`` or ``collect`` rule computes is a summary whether or not it says so
(:ref:`needs_derive_link_chain`), and ``summary = false`` beside such a rule is refused (``needs.derive_invalid``).
``copy = true`` beside ``summary = true`` would copy every summary link into ``links``, which every view reads:
it is a ``needs.config`` warning, and nothing is copied.
With every link type a summary, a :ref:`needflow` without ``:link_types:`` draws none,
its ``needs_flow_link_types`` fallback included.
It is a link type's on every need type: a need type's entry (:ref:`needs_types_fields`) does not give it,
and one that does is a ``needs.config`` warning, the key ignored;
nor does a rule (``derive``, ``derive_by_type``), where it is no role (``needs.derive_invalid``).
A value that is not a boolean is a ``needs.config`` warning, and ignored.
*New in version 9.2.0.*
- ``target_types`` (optional): The need types the links may point to, a list of directive names, such as ``["req"]``.
A link to a need of a listed type, or of a type inheriting from one (``inherits``, transitively), is accepted;
each other link is reported, and kept, one ``needs.link_target_type`` warning at the need it is set in::
Expand Down
Loading
Loading