Skip to content
Hussein Jarrar edited this page Sep 12, 2026 · 2 revisions

v0.32.0

34 changes · 9 Bugfixes, 6 New Features, 19 Chores · 31 points.

Bugfix

  • RADD-1049 Two AI-registry tests fail instead of skipping without the localembed extra — the CI gate's first catch
    The new CI test gate (RADD-1037) runs uv run pytest after uv sync --locked — deliberately WITHOUT the localembed extra (fastembed/ONNX is heavy; the workflow comment states the localembed tests "self-skip on a plain server, mirroring a contributor's laptop"). But…
    ai ci testing · 1 pts · a04efd8f
  • RADD-1046 settings-cleanup proof cannot tell "no fixture" from "regression" — skip loudly on an empty instance
    (audit finding G1). web/scripts/settings-cleanup-proof.mjs needs an existing team — "a team row actually expanded" and the Role-grants-section check depend on one. On the RADD-1025 clean stack (zero teams) it fails 2/N, and nothing distinguishes that from a real regression. It fails loudly rather than vacuously (the…
    proofs web · 1 pts · 883b4523
  • RADD-1031 Holidays do not pause SLA clocks — the RADD-932 claim is false in code
    The RADD-932 commit message says holidays "feed both the timesheet's away cells and business-day SLA resolution." The second half is false: slas/timers.py is pure work-week-days + business-hours-window; the whole modules/slas/ package contains zero references to leave or holidays, and no server module imports…
    leave slas · 3 pts · 12216d01
  • RADD-983 Every sender rides the transport: digest, CSAT and send_email leave the env relay
    (audit findings #5, #8)
    automations csat mailintake notify · 27c58534
  • RADD-1034 Every stranger who emails the desk becomes a pickable person in every people picker
    _sender_user provisions an active UserSource.EMAIL account for any inbound address — correct, it is what makes requesters addressable (RADD-828). But auth/service.list_users applies no source filter, and /users/directory — the endpoint behind every people picker (RADD-769/938) — serves those accounts to every…
    auth mailintake · 2 pts · 743b84b2
  • RADD-1040 RBAC residue: the kernel entity host silently drops query-gated relations, and a dead ProjectMember type survives
    (2026-08-11 week audit, findings A3 + A5). 1. relation_holds_row (sync) treats a relation with no pure holds predicate as not held — correctly fail-closed for today's registrations (comment/worklog/attachment are all pure), but the kernel entity host uses the sync form for generated plugin-entity CRUD…
    auth kernel · 1 pts · ea995897
  • RADD-1030 Participant-shared items are invisible in search: the index mirror never learned @participant
    search/service.py:101 mirrors only ("own", "assigned", "team") onto the search index (d841searchrel added reporter_id/assignee_id/team_id — nothing for participants). In _relation_index_clause, a project where the actor holds item.read@participant compiles a false() arm for that relation, so…
    access-control participants search · 2 pts · 24ae9454
  • RADD-1029 Fix the fixable findings from the first trivy scan
    The first trivy run over v0.31.1 (RADD-1028) found 253 image findings and 3 web findings. Almost everything is unfixed-in-Debian noise (16 CRITICALs are four perl CVEs × four perl packages — perl is only present because postgresql-client-17 depends on it), but five things have fixes published, and all five are…
    23067fba
  • RADD-1010 CLAUDE.md names the attachment entity key as doc_page; the value is page
    The CLAUDE.md preamble described the spec-102 polymorphic attachment parents as "docs registers doc_page". Both halves are stale:
    docs · 1 pts · 236bd6b8

New Feature

  • RADD-1045 The acknowledgement email becomes editable: a settings-backed template through the canned renderer
    (audit finding F4). ACK_BODY and friends are module constants in radd/mailrender.py. Settings → Email configures transport thoroughly and content not at all — IT wanting the ack to carry desk hours and the emergencies phone number is a PR and a release.
    canned mailintake settings · 2 pts · a37b54a0
  • RADD-1041 Related projects in the rail become a display choice — without touching the security model
    (audit finding A4). The Baseline role's item.read@own/@participant simultaneously (a) makes "related" projects appear in the rail (RADD-937's visible_projects) and (b) lets a requester see the ticket they filed. One lever, two concerns: emptying the Baseline to tidy the rail also blinds every requester, and…
    auth projects shell · 3 pts · 2648f52e
  • RADD-1044 Assign next from team: a round-robin automation action, away-aware
    (audit finding F3). Triage is fully manual: no round-robin, no load-based assignment anywhere. Automation graphs can set_assignee to one fixed person — and the LLM classifier node can pick a route — but nothing distributes. Three IT techs, every mail-born ticket unassigned, whoever looks first self-assigns, the rota…
    automations leave teams · 3 pts · a1a572ee
  • RADD-1043 SLA policies can match issue types, so "password reset" and "new starter" stop sharing one clock
    (audit finding F2). SLA policies match on project + priority only (service.matched_policy, first-match by position). Issue types (spec 51) exist per project but policies cannot see them; queues are saved views with no policy attachment. An IT project carrying both "password reset" (target 4 business hours) and "new…
    itemtypes slas · 2 pts · 1b879779
  • RADD-1028 Trivy vulnerability scan in the release pipeline, next to the SBOMs
    RADD-1026 gave every release its inventory; nothing yet reads that inventory for known vulnerabilities. A release should ship with a vulnerability report produced the same way the SBOMs are — automatically, per tag, by the pipeline that built the image.
    6a2af219
  • RADD-1026 Per-release CycloneDX SBOMs, attached to the Forgejo release
    Radd publishes no SBOM at all. The deployable artifact is git.radd-hq.com/radd/radd:<version>, and anyone consuming it (vulnerability scanning, procurement, a future CRA-style ask) has to reverse-engineer what's inside. An SBOM should exist for every shipped version, produced by the same pipeline that ships it.
    07e1d0ad

Chore

  • RADD-1038 The documentation of record is stale: modules.md mis-describes the service desk, CLAUDE.md is ten minors behind
    (2026-08-11 week audit; docs/modules.md is the file PLAN.md twice names as the source of truth): - The spec-30 "known simplifications" bullets claim: no business-hours calendar, no first-match SLA resolution, SLA chips on the detail rail only, email-to-issue deferred, no dedicated queue UI. All five are built (specs…
    docs · 2 pts · 63d8058b
  • RADD-1032 Mail intake trusts From: end to end — read sender-auth verdicts and narrow the subject-key gate
    There is no SPF/DKIM/DMARC/Authentication-Results handling anywhere in the codebase. The design is honest about it ("attribution is not authorisation" — intake._reply_comment routes through create_comment so nothing is granted by a header), but the consequences compose into an impersonation primitive: a forged…
    mailintake security · 5 pts · 6f615e0f
  • RADD-1037 CI never runs the tests: a tag ships whatever the commit contains
    .forgejo/workflows/publish.yaml resolves the version, builds, pushes, publishes the changelog, attaches SBOMs and scans CVEs — and never runs pytest, ruff, or tsc. Every quality gate is a local habit. This week alone shipped three bugs of exactly the class a gate catches: RADD-936 (500 on a filter…
    ci · 3 pts · 557ffb1f
  • RADD-1025 Two one-command local stacks: your data, or a clean one
    One command to run the instance you have been building against, and one to run an empty instance — toggleable, with neither able to destroy the other.
    d8923d15
  • RADD-1025 Two one-command local stacks: your data, or a clean one
    One command to run the instance you have been building against, and one to run an empty instance — toggleable, with neither able to destroy the other.
    f42a186c
  • RADD-1024 Mermaid diagrams in the wiki
    Diagrams in wiki pages, written as text.
    dcb119d8
  • RADD-1023 A code fence written with a file extension highlights nothing
    982462c8
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    c7bb7eac
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    c49992ef
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    a0512a6b
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    0a4b68b4
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    d472576d
  • RADD-1022 The importer meets a real Confluence: five failures a fixture could not produce
    What was wrong. The first use against the live instance (confluence.mtl.ad.cinesite.com, space PIP, 6099+ pages) failed two ways: choosing "specific pages" showed an empty tree with no error, and "whole space" reported a bare failed with no reason. Every test passed, because every test was built from hand-written…
    df7d2f0d
  • RADD-1021 The import wizard UI
    /settings/confluence-import — the surface that makes the four phases operable.
    8a9b5071
  • RADD-1014 Snapshot: one scope for spaces, subtrees and page sets, downloaded once
    Cache-first, as spec 100 established: a selection is downloaded once into confluence_snapshot_pages, and every later step — profiling, the macro census, planning, dry runs, the real run, re-runs after a mapping fix — reads that cache. Nothing after this phase touches the network.
    6f7ee1e9
  • RADD-1019 Three new page extensions: unsupported-macro, expand, and items
    Three radd:* extensions the importer needs and the wiki gains permanently. Each ships its declaration and its renderer in the same commit — tests/test_page_extensions.py compares the TypeScript registration list to the kernel's in both directions, so a name declared without a renderer fails the build. That test is…
    1281f88b
  • RADD-1015 Storage format to markdown: the converter
    Confluence storage format — the XHTML dialect with ac:/ri: elements — converted to the markdown pages.body stores. Pure, unit-tested, no DB and no network, so it can be run over the snapshot cache repeatedly as mappings change.
    dc2a9c16
  • RADD-1013 Confluence connections and a Server/DC client
    The bottom of the importer: DB-row connections and a client that can actually talk to Confluence Server/DC.
    12cf7617
  • RADD-1012 Pages gain an external identity and the import seams a faithful import needs
    Four seams pages does not have, all of which spec 117 needs before a single Confluence page can be written. Three of them comments already closed years ago with CommentCreate.author_id + created_at; the fourth is new.
    9aecb329

Changes from v0.31.1 to v0.32.0.


Mirrored from project.radd-hq.com on 2026-09-12. Documentation is written there; this copy is regenerated by scripts/publish_wiki.py and hand edits do not survive it.

Clone this wiki locally