Skip to content

Add Event abbreviation and surface it in compact/event contexts - #1995

Merged
maebeale merged 1 commit into
mainfrom
maebeale/event-abbreviation
Jul 15, 2026
Merged

Add Event abbreviation and surface it in compact/event contexts#1995
maebeale merged 1 commit into
mainfrom
maebeale/event-abbreviation

Conversation

@maebeale

Copy link
Copy Markdown
Collaborator

🤖 suggested review level: 3 Read 📖 small additive change: a new column + a display helper applied in a few compact spots, with a fallback to the full title

What is the goal of this PR and why is this important?

How did you approach the change?

  • Event#abbreviation (string) + a form field + policy param.
  • EventDecorator#compact_labelabbreviation.presence || title. Applied to:
    • the revenue report's per-event rows,
    • the event dashboard and background header links (full title preserved as a title= tooltip).
  • The org profile's admin-only "Program status by event" chips label each event by its compact_label and classify the org as of that event's start_date.

Anything else to add?

  • Only events that actually have an abbreviation are affected anywhere; everything else still shows the full title.
  • Screenshots to follow.

Adds an admin-set short code (e.g. "TOS205") to events and uses it wherever a
full event title is too long or repeated across many events, falling back to the
title when no abbreviation is set.

- Event#abbreviation column + event-form field + policy param.
- EventDecorator#compact_label => abbreviation or title; used on the revenue
  report's per-event rows and the dashboard/background header links (full title
  kept as a tooltip).
- Org profile "Program status by event" chips: classify the org as of each
  event's start date and label the chip with the event's compact_label.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 15, 2026 05:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

maebeale added a commit that referenced this pull request Jul 15, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
def compact_label
object.abbreviation.presence || object.title
end

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Single source of truth for the abbreviation-or-title fallback. Callers pair it with title="<full title>" so an unfamiliar abbreviation is never ambiguous.

# already-loaded affiliations so a profile can classify many events without an
# N+1. No facilitator affiliation starting before the date => :new; an earlier
# one still active on the date => :ongoing; all earlier ones ended => :reinstated.
def facilitator_status_as_of(date)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Computed in-memory over the already-loaded affiliations (not the DB-backed Organization#facilitator_status_on) so classifying a page of ~9 events on the profile does not fire 2 queries per event.

@maebeale
maebeale marked this pull request as ready for review July 15, 2026 05:12
@maebeale
maebeale merged commit 0bee35a into main Jul 15, 2026
3 checks passed
@maebeale
maebeale deleted the maebeale/event-abbreviation branch July 15, 2026 05:21
maebeale added a commit that referenced this pull request Jul 31, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 3, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 3, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 4, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 6, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 8, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 9, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 11, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 15, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 16, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 17, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 18, 2026
New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale added a commit that referenced this pull request Aug 18, 2026
… annual report (#1993)

* Remove program status from org-wide UI

New/Reinstate/Ongoing can only be determined relative to a specific event, so
showing it as a global org attribute was misleading. Per-event program status is
surfaced on the org profile in a separate PR (event abbreviations, #1995).

- Drop the admin-only "Program" column from the org index.
- Drop the now-orphaned Organization.program_statuses_by_id bulk classifier.
- Drop the "Program status" block from the org edit form's Affiliations section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Show affiliated-since as merged periods; simplify org status to 3 values

Affiliated-since was already affiliation-derived, but showed a single
Mon YYYY – Mon YYYY range. Admins need the real shape of an org's history —
including gaps — and a status vocabulary that isn't event-specific.

- AffiliationPeriods service merges affiliation intervals into periods and
  formats them as year-based ranges: a lone ongoing period shows "Mon YYYY"
  (this year) or its start year; multi-period lists are year-only, e.g.
  "2010-2012, 2026". Falls back to the org's start_date, then blank.
- Applied on the org show page, index column, and edit form; the edit form's
  live preview (affiliation_dates_controller.js) mirrors the same formatting.
- Simplify OrganizationStatus to Active / Formerly active / Unknown. Data
  migration remaps existing statuses (Reinstate->Active, Inactive/Suspended->
  Formerly active, Pending->Unknown) then drops the retired records; the
  affiliation status-sync callback and seeds follow the new names.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Scope affiliated-since periods to the org form, leaving the person form's range

The affiliation-dates Stimulus controller is shared with the person edit form,
whose "Affiliated since" stays a single Mon YYYY range. Gate the merged-periods
formatting behind a `periods` value the org form sets, so only the org form's
live preview and server render use periods.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Render org affiliated-since server-side only; drop the JS period logic

Keeping the merge-and-format logic in both AffiliationPeriods and the Stimulus
controller was a duplication smell. The org form's "Affiliated since" doesn't
need a live preview now that it's coarse year-ranges, so render it server-side
via the decorator and leave that field untouched by JS (a `serverAffiliatedSince`
value gates it). The person form keeps its live single Mon YYYY range.

AffiliationPeriods is now the single source of truth. Replaces the org
affiliation-dates system spec with a request spec asserting the server render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Show "Program since" (facilitator periods) on org index/show/edit

Replaces the org index "Affiliated since" column with "Program since" — the
org's facilitator-affiliation history as merged year-based periods (e.g.
"2015-2018, 2024") via a new OrganizationDecorator#program_since_display. Adds a
"Program since" row to the org show page, and converts the edit form's
"Facilitations/program since" value to the same period format.

Both org-form "since" fields are now server-rendered, so the affiliation-dates
Stimulus controller is dropped from the org form (it still drives the person form).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add general "Program status" chip + index bucket filter; New→indigo

Introduces the org-wide program status (from the stored organization_status,
with Unknown/blank shown as "Never active") as a colored chip, and shows it
before the per-event New/Ongoing/Reinstate chips under a single "Program status"
heading on both the edit form and a new admin-only block on the org profile
(per-event chips moved out of the events-attended cards).

- Index: a "Program status" chip under the "Program since" date (GA), plus a
  staff-only bucket filter — Active / Formerly active / Never active /
  Formerly + Never active — backed by an Organization.program_status scope
  (Unknown and no-status both count as never active).
- Palette: New moves green→indigo site-wide (DomainTheme + scholarship decorator)
  so it never collides with the green "Active" chip; general chip colors are
  green / orange / gray.
- Per-event chips link to the event background report in a new tab (placeholder
  for the in-development attendance report).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Move profile program-status chip assertion to the show page

The per-event chips moved out of the lazy events-attended frame into the
admin-only Program status block on the show page; point the spec there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Link per-event chips to the event dashboard; gate index status chip to admins

- Per-event program-status chips now open the event dashboard (the canonical
  event admin home) in a new tab, instead of the background report — still a
  placeholder for the in-development attendance report.
- The org index "Program status" chip under the Program since date is now
  admin-only (manage?), matching how program status is treated elsewhere.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Show Program since years in a yellow chip on the org index

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Colour the index Program-since chip by status; rename Designations→Sectors

- Merge the separate year + status chips into one: admins see the facilitator
  years coloured by org status (green Active / orange Formerly active / gray
  Never active), falling back to the status label when there are no years;
  non-admins keep a neutral yellow year chip.
- Rename the index "Designations" column to "Sectors" and stop showing the
  windows-type pill there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Swap the windows-type index filter for Sector + Age group dropdowns

Replaces the "Windows audience" dropdown with a Sector dropdown (sector_names_all)
followed by an Age group dropdown (category_names_all over AgeRange categories) —
both wired to the existing search scopes. Options are loaded in set_index_variables.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Aggregate org sector/age-group displays + filters over affiliated people

Sector and age-group displays and filters now reflect tags on the org itself and
on any affiliated person (not just the org's own tags):

- Index sector column now uses all_sectors (aggregate), matching the age-group
  column and the org profile (which already aggregate).
- New Organization scopes sector_name_including_people / age_group_name_including_people
  back the index Sector / Age group dropdowns (params sector_name / age_group_name).
- affiliated_sectors now aggregates over all affiliated people (people through
  affiliations) rather than only those with user accounts, so all_sectors matches
  the age-group aggregation and the filters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Roll up only affiliated people's PRIMARY sector/age group to the org

Sectors and age groups shown (and filtered) on the org index/profile are now:
tagged directly on the org (any), OR an affiliated person's PRIMARY tag —
affiliated people's non-primary sectors and additional age groups no longer
roll up.

- affiliated_sectors: only each person's primary sector (they have at most one).
- all_additional_age_groups: org's own additional only (people contribute their
  primary via all_primary_age_groups, not additional).
- sector/age-group filter scopes: org-direct OR affiliated person's primary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Keep the 6 legacy org statuses; bucket them for the program-status UI

Reverts the org-status simplification: restores the six-value constant, drops the
data migration (leaving the records/mappings as-is), and points the sync
callbacks and seeds back at "Inactive".

The program-status chip and index filter now collapse the stored six values into
three display buckets via OrganizationStatus::PROGRAM_STATUS_BUCKETS
(Active/Reinstate → Active, Inactive/Suspended → Formerly active,
Pending/Unknown/none → Never active), so the data is untouched while the UI still
reads as Active / Formerly active / Never active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Rename EventRegistration organization_status scope to organization_linking_status

It filters by the registrant's org-linking status (linked/pending), which is
unrelated to the org's own OrganizationStatus — the old name was confusing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Derive program status from facilitator affiliations, stored status as fallback

The program-status chip (OrganizationDecorator#organization_status_bucket) and
the index filter (Organization.program_status scope) now compute from facilitator
affiliations: an active facilitator affiliation => Active, facilitator
affiliations but none active => Formerly active. Only when an org has NO
facilitator affiliations do they fall back to the stored organization_status
bucket — so a manual "Active" still backs an org into Active, and Pending/Suspended
keep their buckets. Manual override and the stored data are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Point per-event program-status chips at the participation report; drop dead windows-type filter

- The per-event chips now open the event participation report filtered to that
  event (participation_events_path event_id: …, with a dashboard back-link),
  replacing the dashboard placeholder now that the report exists on main.
- Remove the now-dead windows_type_name filter from Organization.search_by_params
  and the unused :windows_type eager-load on the index (the windows-type column
  and dropdown were both removed earlier).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Use a real stored status name ("Inactive") in search spec

"Formerly active" is a display bucket, not a stored OrganizationStatus
value; the search spec should set up an org with an actual legacy status.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Admin-only-blue org index rows (like people); bullet the Program status tooltip

- The org index is admin-only (OrganizationPolicy#index? => admin?), so tint each
  row admin-only bg-blue-100 unless the org is published, mirroring the people
  index. Simplifies the Program-since cell (drops the now-dead non-admin branch).
- Break the edit-form "Program status" tooltip's New/Ongoing/Reinstated onto their
  own bulleted lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Live-update the org edit form's Program status chip

The affiliation-dates Stimulus controller was dropped from the org form
when "Affiliated since" moved server-side, which also stopped the Program
status chip from reacting as facilitator rows are edited. Re-attach the
controller and derive the chip's bucket client-side (mirroring
OrganizationDecorator#organization_status_bucket): active when any
Facilitator row is still active, formerly active when they've all ended,
else the stored-status fallback. Bucket labels/classes come from the
decorator so no theme classes are hard-coded in JS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Clarify the Reinstated tooltip: re-engaging after being formerly active

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Document org affiliation/program-status semantics (ADR-0001); gate per-event chips to trainings

ADR-0001 pins the definitions we kept re-deriving: affiliated-since (all
affiliations), program-since (facilitator affiliations), the org-wide status
bucket, and the per-event New/Ongoing/Reinstate status — including that it's
per-event (not per-registrant, no self-exclusion) and only meaningful on
facilitator-training events.

Per that decision, the per-event "Program status by event" chips now render
only for facilitator_training events the org is represented at.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Live-update the org form's Affiliated-since periods

The org edit form now live-updates "Affiliated since" as merged year-based
periods (mirroring AffiliationPeriods, with the org start_date fallback),
alongside the already-live program-status chip.

Also adds a request spec asserting the event-registration linked-org chip links
to the org profile (the chip itself is rendered by main's #2077).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix events-section spec: gate the program-status chip event to trainings

Per-event program-status chips only render for facilitator_training events
(ADR-0001), but this example created a plain event, so no chip appeared and the
"TOS205" assertion failed. Make the event a training so the chip renders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Reorder per-event program-status chip to "Mon YYYY · Status · Event"

Leads with the event date, then the facilitator-program status, then the event
label — e.g. "Aug 2026 · Ongoing · PES205" — instead of "Ongoing as of Aug 2026 · …".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Remove fallback to org status

* Keep PEOPLE_TAGGINGS from orphaning the AGENCY_TYPES doc comment

The constant landed between the AGENCY_TYPES explanation and the constant it
documents, so that comment read as if it described the preload nest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Record in ADR-0001 what main's affiliation changes settle

Rebasing picked up two changes that bear on the program-status decisions.
#2176 dates new affiliations to the actual date rather than the 1st, which
retires most of the date-precision caveat — but only for rows created since,
so historical rows can still misread as Ongoing. #2194 restricts facilitator
minting to training registrations, which is what makes keying status off
facilitator affiliations alone a read on training participation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Stop ai/test aborting when a branch deletes a system spec

The system-spec selection reads the branch diff, which lists deleted files too,
so a branch that removes a system spec handed rspec a path that no longer
exists and the whole run died with a LoadError before any example ran.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Render "Art program since" as one value everywhere, at month precision

The profile showed merged periods while the edit form built its own
earliest-start-to-latest-end span, under the same label. That was not two
formats of one fact: for an org that facilitated 2015-2018, lapsed, and
returned in 2024, the form rendered "Aug 2015" and the gap disappeared,
because facilitation_end_date is nil whenever any facilitator is active.

Give AffiliationPeriods a month precision and let both surfaces read the one
decorator method, so the exact month a program started or lapsed survives and
the two cannot drift again. The Stimulus mirror follows suit, which drops one
of its two rendering paths.

The same date-range span was copy-pasted three times across the org and person
forms; the two remaining person-form copies become decorator methods, and the
org decorator's now-unused facilitator date readers go.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Name the participation back-link's org param so it can't filter

Rebasing picked up #2075, whose report subnav forwards REPORT_SUBNAV_PARAMS
between report pages — and that list includes organization_id, which the
attendees index treats as a real filter. This branch had been passing
organization_id on the participation URL purely as a back-link breadcrumb, so
the two together meant: org profile -> program-status chip -> Attendees tab
silently narrowed the attendee list to that org, with no visible filter saying
why. Neither change is wrong alone.

Rename the breadcrumb to return_organization_id, which the subnav does not
carry and nothing reads as a filter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Make program status one rule anchored on the event's date

Several code paths decided New/Ongoing/Reinstate their own way. Two of them
excluded the registrant's own affiliation, differently, and the dashboard
re-anchored on that affiliation's start date instead of the event's — so the same
org at the same event could read Ongoing on the onboarding matrix and New in the
dashboard pie, and the pie's answer moved when a different registrant signed up.
FacilitatorProgramStatus is now the only classifier. Dropping self-exclusion is
safe because a training's minted affiliation starts on the training date and
"before" is strict, so a first-time org still reads New at its own first training.

Statuses now carry their own reasoning, so every badge hovers to explain the
anchor date, what made the program active, and the facilitator history behind it.
Cross-event lists have no event to anchor on, so they read as of Jan 1 and say so
rather than quietly using "today" — which the attendees filter was doing while its
column would have said otherwise.

Adds the annual-reporting page these counts were being assembled by hand for:
organizations by status at each training, summed per year, plus the distinct-
organization view, because an org at three trainings shouldn't silently count as
three programs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Trim two verbose decorator display-method comments

The "affiliated since"/"art program since" doc comments restated inferable
detail (single-source-of-truth intent, repeated N+1 hint); keep the
non-obvious why (precision choice, fallback chain) in fewer lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Tighten verbose comments across org/program-status code

Trim leaning-verbose comment blocks (agency-type folding, self-funding org,
program-status scope/method, agency_type_option, the affiliation-dates JS
header + periodsLabel) to keep only the non-obvious why: drop restated code,
duplicated gotchas, and the stale "confirm with the team" hedge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Scope org @organization_events through authorized_scope

Per review: wrap both @organization_events queries (show's program-status
block and the edit form's per-event chips) in authorized_scope so EventPolicy
visibility is applied consistently with #index, instead of the manual
manage?/persisted? gate. Both pages are admin-only, so the result is identical
for the actual audience; the scope adds defense-in-depth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Restore affiliations column header on the org edit form

Main's rebase brought in the xl:grid affiliations/_fields, which hides
per-field labels at xl+ and relies on affiliations/_header for the column
labels. The org form renders that grid partial, so it needs the header too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Scope org events-section query through authorized_scope

Applies EventPolicy visibility to the profile "Events attended" section,
matching #index and the program-status block. The org show page is admin-only,
so the result is unchanged; the scope adds defense-in-depth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Match org affiliation-editor system specs to main's grid fields

Main's affiliations/_fields (pulled in by the rebase) renders the title as an
<input> (not a textarea) and only shows an inline "Remove" for new rows —
persisted rows are removed via the gear's affiliation editor. Update the two
system specs: use the input selector, and drive "Never active" by retitling the
sole facilitator instead of an inline remove that no longer exists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Anchor recipients-page program status on the event's own date

The recipients charts cover a single event, but AttendeesBreakdowns judged
program status as of the start of the year — so the card's new note claimed
a basis the numbers didn't have, and the same org read differently here than
on the event's dashboard.

Also point the New pie slice at the indigo the theme moved program_new to,
so the slice and the badges beside it stop disagreeing.

* Trim comments to the non-obvious, and catalogue the shipped features

The new program-status code carried long headers restating the rule the ADR
already pins down; the ADR is the source of truth, so the code now points at it
and keeps only what the code can't say itself.

ADR D7 gains the corollary the recipients-page bug proved was needed: the
year-anchor fallback is for surfaces that genuinely span events, not for every
cross-event class.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants