Skip to content

fix(display-board): stop the organigram naming a nested post as a team - #382

Merged
mindsers merged 2 commits into
mainfrom
fix/organigram-nested-post-not-a-team
Sep 2, 2026
Merged

fix(display-board): stop the organigram naming a nested post as a team#382
mindsers merged 2 commits into
mainfrom
fix/organigram-nested-post-not-a-team

Conversation

@mindsers

@mindsers mindsers commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

On the organigram board document, a personal role nested under another personal role was printed on the band's « ÉQUIPES » line, so the sheet announced a post as if it were a team:

Coordinateur du programme des     Gérard HUOT   ADJOINT Christian VARDON
discours publics
                                  ÉQUIPE Responsable du programmes des services   ← a post, not a team

Why it happened

A band's rows are not all teams, but ServiceWithTeams received band.rows wholesale and named every one of them.

The settled model treats a child personal role as an adjoint arrangement, and the band was already folding that child's titulaire into its ADJOINTS. So the same person appeared twice on the row: once correctly as an adjoint, and once as the name of a team that does not exist. In the example above, ADJOINT Christian VARDON and ÉQUIPE Responsable du programmes des services are the same post printed two ways.

Filtering the ÉQUIPES line down to group roles therefore loses nobody.

The fix

Both halves of the rule move into organigram-layout.ts:

  • teamRows(rows) — the rows a band names as teams. Group roles only.
  • bandAdjoints(node, rows) — its own deputies, then the leaders of everything beneath it: a team's préposé and a nested post's titulaire alike. This is the fold that makes the filter safe.

The PDF had the identical bug. OrganigramView.tsx and OrganigramDocument.tsx carried separate private copies of the adjoint fold, so fixing only the screen would have left the printed sheet wrong. Both now call the shared helpers, and neither can drift from the other again.

Filtered at render time rather than in toLayout, because a collector band (node: null) prints the same rows as full lines, people and all — there a personal role does belong, and filtering upstream would have made posts vanish from those sections.

Verification

TDD as the regression rule requires: 5 failing teamRows tests, then 6 failing bandAdjoints tests, each watched red before implementing. The bandAdjoints set pins the invariant that makes the filter safe — a nested post's titulaire still reaches ADJOINTS — so nobody drops off the sheet. It also covers the fold's existing edges: the band's own deputies come first, someone already leading the band is not repeated, someone leading two teams is listed once, and plain members are ignored.

End to end on the board viewer, by temporarily nesting a personal role under Audio/Video in a development database:

before   ÉQUIPES Perches, Estrade, Sono, Responsable du programme des services
after    ADJOINTS Sébastien ROUX, Marc DUPONT, Jérôme MULLER
         ÉQUIPES Perches, Estrade, Sono

Full gate green: typecheck, lint, boundaries, aggregate-boundaries, tenant-scoping, server-barrel-exports, service-test-coverage, file-sizes, permission-coverage, unit, integration — plus biome check, which the pre-commit hook enforces and CI does not run.

One judgement call worth a second opinion

A nested post with nobody seated now prints nowhere: there is no adjoint to fold, and it is no longer named as a team. That follows the sheet's stated philosophy of naming who to ask for, and a wrongly-labelled name was arguably worse than none. If an unseated post should still print its name somewhere, that is a different change and a deliberate decision rather than a bug fix.

A personal role sitting under another personal role was printed on the
band's « ÉQUIPES » line, so the sheet announced a post as if it were a
team: « ÉQUIPE Responsable du programme des services ».

A band's rows are not all teams. The settled model treats a child
personal role as an adjoint arrangement, and the band already folds that
child's titulaire into its ADJOINTS — so the person was on the sheet
twice, once correctly as an adjoint and once as the name of a team that
does not exist. Filtering the ÉQUIPES line to group roles loses nobody.

Both halves of the rule move into organigram-layout as `teamRows` and
`bandAdjoints`. The screen view and the PDF carried identical private
copies of the adjoint fold, which is how a fix lands in one renderer and
not the other; now neither can drift.

Filtered at render time rather than in `toLayout`, because a collector
band (`node: null`) prints the same rows as full lines, people and all —
there a personal role belongs.

Verified on the board viewer by nesting a personal role under
Audio/Video: its name no longer appears among « Perches, Estrade, Sono »
and its titulaire shows up in ADJOINTS instead.
From the review of #382. `BandBlock.rows` documented itself as "Rendered
beneath, in order", which is true and says nothing about the one property
a caller has to know: the list mixes group roles with personal roles, and
treating them alike is exactly the bug this branch fixes.

Documented rather than encoded in the type. Splitting the field would
express the invariant properly, but a collector band prints the same list
unfiltered as full lines, so the split would have to be undone at that
call site — a worse trade for a two-caller helper. Left as a note here
and a backlog item.
@mindsers
mindsers merged commit 907a052 into main Sep 2, 2026
7 checks passed
@mindsers
mindsers deleted the fix/organigram-nested-post-not-a-team branch September 2, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant