Previous fix (col=1 on the group) didn't work — Odoo still rendered
the group's string as a left-column label inside the form sheet's
flow, so the textarea got pushed into a narrow right column. The
summary field looked entirely missing because its content split
between the button row (on the right) and the textarea (collapsed
nowhere visible).
Right idiom (lifted from Odoo's own mail.compose.message wizard):
WIDE textareas live directly at the form level, not inside <group>.
Section titles use <separator string="…"> which renders as a
horizontal divider with the label above. The textarea then takes
the full sheet width naturally.
Same pattern applied to bulk mode for consistency.
Also moved Personal Note into the top compact group with Owner /
Owner Email since it's a one-line input that belongs with the
header info, not pretending to be a wide section.
Bumps fusion_helpdesk_central to 19.0.2.3.2.
The Findings and Summary fields rendered at half-width because their
enclosing <group> defaulted to col="2" — Odoo reserves a label column
even when the field has nolabel="1", so the textarea was squeezed
into the right half of the dialog while the left half sat empty.
Switch both groups to col="1" so the field uses the entire group
width. Also tag both fields with widget="text" explicitly (it was
inferred from the Text field type, but being explicit makes the
intent obvious to anyone reading the view) and migrate the button
row to a flex div so the helper text aligns with the button vertical
center.
Bumps fusion_helpdesk_central to 19.0.2.3.1.
The old flow fired OpenAI on wizard open with just ticket + chatter,
so the AI summary was just a paraphrase of what the user originally
reported — your engineering analysis (scope, limitations, recommended
approach) never made it to the owner. Restructure to a two-step flow:
1. Open wizard → empty findings + empty summary, NO OpenAI call
2. You write findings: scope / effort / approach / risk
3. Click 'Generate Summary from Findings' → OpenAI runs with
ticket + chatter + findings, where the prompt explicitly tells
the model to weight findings MORE THAN the original report
4. Review/edit, then Send
Bulk wizard mirrors the flow per line: each row gets its own
findings + summary, one 'Generate All Summaries' button fans out
parallel OpenAI calls using each line's own findings.
Updated SUMMARY_PROMPT to:
- Tell the model the support engineer's findings are authoritative
- Emit a bullet structure that leads with the recommendation, not
the user's restated ask
- Side with findings over the original report when they conflict
New tests cover:
- default_get does NOT fire OpenAI (regression guard for auto-AI)
- Findings text actually reaches the OpenAI prompt
- Send works with a manually-typed summary (no AI in the loop)
- Existing bulk + validation paths still pass with the new shape
Also folds in the deferred code-review #7: ThreadPoolExecutor now
explicitly cancels pending futures on timeout via
shutdown(wait=False, cancel_futures=True) so a slow OpenAI day can't
hold the wizard open for ceil(N/workers)*15s.
Bumps fusion_helpdesk_central to 19.0.2.3.0.
Smoke-tested live on nexa: opening the wizard makes zero OpenAI calls;
clicking Generate with findings='My findings: scope is XL, ~8h' makes
exactly one call and the findings text is verifiably in the prompt
body received by call_openai_chat.
Ships the design spec at docs/superpowers/specs/2026-05-27-owner-approval-flow-design.md.
What's new on central (fusion_helpdesk_central 19.0.1.2.0 -> 19.0.2.0.0):
- Engagement model: 8 new fields on helpdesk.ticket (state, snapshotted
owner email/name, single-use UUID4 token, sent/reminded/decided
timestamps, AI summary, stored-computed turnaround hours).
- Wizard: single + bulk modes on one fusion.helpdesk.engagement.wizard
TransientModel with a child wizard.line for per-ticket bulk summaries.
default_get pulls the OpenAI summary on open; AI fan-out for bulk is
parallel via ThreadPoolExecutor (max 5 workers, 30s overall cap).
- OpenAI client in utils.py — stdlib urllib, 15s per-call timeout, every
failure collapses to '' so the wizard's manual-summary fallback fires.
- Public portal: /fusion_helpdesk/engagement/<token>/<decision> GET +
POST, four branded standalone QWeb pages (confirm/done/invalid/error).
Token is single-use, cleared on confirm. Decision posts a public
comment attributed to the resolved owner partner; chatter propagates
to the employee's My Tickets thread per the "fully visible" UX choice.
- Mail templates (single + bulk) with magic-link buttons. Bulk template
renders one card per ticket, each with its own approve/reject URL.
- Reminder cron: daily, single-shot per engagement, configurable via
fusion_helpdesk_central.engagement_reminder_days ICP (default 3, 0
disables).
- Reporting dashboard: pivot/graph/list/kanban over helpdesk.ticket
filtered to engaged ones, with avg-turnaround measure. Menu lives
under Helpdesk > Reporting > Owner Engagements.
- Client_key extended with owner_email/owner_name fields; ticket.create
upserts them from the client-side piggyback (no new sync endpoint).
- 100% coverage on utils + integration tests on wizard, controllers,
re-engagement, cron, computed turnaround. OpenAI mocked in CI.
What's new on client (fusion_helpdesk 19.0.1.7.1 -> 19.0.2.0.0):
- Two new ICP settings: fusion_helpdesk.owner_email / .owner_name with
a new "Owner Approval" block in Settings > Fusion Helpdesk.
- controllers/main.py::submit piggybacks both keys on every ticket
payload so central keeps client_key.owner_email/name fresh
automatically.
Verified live end-to-end on entech -> nexa: payload upsert, wizard with
mocked AI, action_send, portal GET/POST/GET-again cycle, second click
hits the friendly invalid-token page. Token entropy = 122 bits (UUID4).