Skip to content

feat: agent-driven forms & check-ins authoring (full web parity)#35

Merged
xergioalex merged 35 commits into
mainfrom
feat/agent-forms-checkins-authoring
Jul 6, 2026
Merged

feat: agent-driven forms & check-ins authoring (full web parity)#35
xergioalex merged 35 commits into
mainfrom
feat/agent-forms-checkins-authoring

Conversation

@xergioalex

Copy link
Copy Markdown
Member

Summary

Adds a complete agent-driven forms & check-ins authoring surface to the CLI, bringing it to 100% parity with the Dailybot web editor. An agent (or human) can now create, fully configure, and edit forms and check-ins — questions, workflow, permissions, scheduling, AI settings, sharing — entirely from dailybot, with every field validated client-side and round-tripped against the API.

This branch also carries the installer minimum-version feature (kept here per request, not split out).

What's included

Check-in authoring

  • checkin create / checkin config — full config: schedule, required participants (users/teams), report channels, frequency (weekly + --frequency-advanced monthly/custom + --cron), reminders (count/interval/condition/tone), submission rules, privacy, intro/outro, and smart/AI (--smart, --intelligence, --max-clarifying).
  • checkin questions add/edit/delete/reorder, archive, show.

Form authoring

  • form create / form config (new) — full web-Setup parity: workflow states (--state "Label:#color"), three permission audiences (edit / see / change-states, incl. restricted with users/teams), anonymous / public / brand / require-identity, approval flow + approvers, ChatOps command, activate/deactivate, report channels.
  • form questions add/edit/delete/reorder, archive, get (rich panel).

Questions (both resources)

  • 4 types (text, multiple_choice, boolean, numeric), blocker tagging.
  • Report title (--short-question) required by default, or --ai-short-question to opt into AI generation; explicit titles preserved.
  • Variations (alternate phrasings).
  • Conditional logic--logic-file or inline --jump-if-equals/--jump-to/--else-jump-to; full operator catalog, jump_to / trigger_checkin / trigger_form actions, forward-only jumps, required rules_else.

Ergonomics & robustness

  • Resolve people by name, email, or UUID everywhere (participants, approvers, audiences) via ?include_email=true.
  • --no-approvers to clear the approver list; full-replace semantics for audiences/approvers.
  • public_url surfaced after enabling public responses; 3 report-channel cap enforced client-side.
  • Fixed a real bug: question reorder was a silent no-op (wrong request field) for both forms and check-ins.
  • ~30 friendly error-code mappings (checkin_requires_participant, unknown_field, anonymous_irreversible, too_many_report_channels, short_question_required, question_uuids_incomplete, workflow/permission/command codes, …).

Installer

  • Minimum-version pin (>=X.Y.Z) support in install.sh / install.ps1 / pip spec, documented in the README.

Verification

  • Full gate green: ruff + ruff format --check + mypy + 692 tests.
  • Every surface live-verified end-to-end against a real org (create → configure → edit → reorder → archive), including a delete-all-and-recreate pass across all config categories.
  • Developed in lockstep with the API team; each gap found was fixed server-side and re-verified.

Risks

  • No backward-compat breaks: form edit is unchanged (a subset of the new form config); all new flags are optional. The one behavior change is that authoring a question now requires --short-question or --ai-short-question (intentional, per product direction).

Notes

  • Reference docs updated: docs/API_REFERENCE.md, README, and the vendored dailybot skill pack (forms/checkin/channels).
  • No new runtime dependencies (no Homebrew formula change needed).

🤖 Generated with Claude Code

xergioalex and others added 30 commits July 4, 2026 15:13
…f PLAN_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… of PLAN_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ckins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…heckins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…LAN_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… PLAN_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…AN_agent_forms_checkins_authoring

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The finalized API contract confirms POST /v1/forms/create/ accepts
report_channels in the body, so drop the follow-up PATCH /config/ round-trip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… is canonical

The API team confirmed every read endpoint (form detail, form list, and all
authoring responses) returns the canonical question shape, so the
type/label/is_optional/choices normalization in the shared render helper is no
longer needed. print_checkin_detail is untouched — it reads the templates
endpoint, which is a separate shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## Summary
Let users pin a minimum version (not just an exact one) when installing via
install.sh, install.ps1, or pip. `>=1.15.0` installs the newest release at or
above the floor; the existing exact-pin forms (`1.15.0`, `==1.15.0`) are
unchanged.

## Change Log
- install.sh: split an optional `==`/`>=` operator from the numeric token;
  validate only the number against the existing charset; reject unsupported
  operators (<, >, <=, ~=, !=) up front. For `>=`, resolve the latest release
  tag and compare with `sort -V`, downloading the binary only when it satisfies
  the floor, otherwise deferring to `pip install "dailybot-cli>=<v>"`.
- install.ps1: same operator parsing; emit `dailybot-cli>=<v>` so pip resolves
  the floor natively (pip-only path, no binary resolution needed).
- Regenerated install.sh.sha256 / install.ps1.sha256 sidecars.
- README + RELEASE_AND_DISTRIBUTION: document exact vs. minimum-floor pinning
  for every install method, plus the specifier-parsing/security note.

## Risks
- Backwards compatible: empty = latest, bare/`==` = exact (unchanged). New
  behavior is additive behind the `>=` prefix.
- Injection-safe: whitespace stripped then the number is charset-validated
  before reaching any pip/URL command; verified `1.0.0; rm -rf /` aborts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## Summary
The API team finalized the forms & check-ins authoring contract
(docs/PUBLIC_API/AUTHORING_CONTRACT.md). This aligns the CLI to it: canonical
question shape on every read path, is_blocker authoring, resolved participants,
archive/list filtering, and the new canonical check-in detail endpoint.

## Change Log
- api_client: add get_checkin_detail (GET /v1/checkins/<uuid>/detail/); thread
  include_archived into list_forms and list_checkins.
- authoring_helpers: thread is_blocker through build_question,
  build_question_edit_fields, parse_questions_file, and the interactive builder.
- display: render {label,value} choices + a Blocker column in the shared
  question table; rewrite print_checkin_detail for the canonical /detail/ shape
  (resolved participants, attached report channels, is_archived); add a Status
  column to the forms list; enrich form detail; fix Created-vs-Updated panel
  titles on edit/config.
- commands: --include-archived on `form list`; --blocker/--no-blocker on
  form/checkin question add+edit; migrate `checkin show` to get_checkin_detail;
  panel says "updated" on form edit / checkin config.
- BREAKING (server): choices are now [{label,value}] on all read paths — the
  shared renderer reads .label; form-submit/TUI prompt paths already tolerated
  this. reorder now 400s on unknown UUIDs (server-side; no client change).
- tests: +18 (choices/blocker rendering, get_checkin_detail, include_archived,
  is_blocker authoring, participants, archived status); updated fixtures for the
  new shapes.
- docs: API_REFERENCE + vendored forms/checkin SKILL packs.

## Risks
- Additive on read (required/index/is_blocker/participants/report_channels are
  new keys). The one breaking change (choices shape) is handled by a single
  canonical renderer; no other read site indexes choices as strings.
- checkin show now depends on the /detail/ endpoint — validate against a backend
  carrying the finalized contract before release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oint

## Summary
`channels list` returned "No report channels available" even for orgs with
Slack channels configured. The `/v1/report-channels/` endpoint returns
`{"channels": [...], "total": N}`, but the client only unwrapped a bare list
or `{"results": [...]}` and silently fell through to `[]`.

## Change Log
- api_client.list_report_channels: also unwrap the `channels` key (keep the
  `results` and bare-list paths for compatibility).
- Added a regression test for the `{channels, total}` shape.
- Corrected the docs/API_REFERENCE response shape ({channels:[{id,name,platform,
  type}], total}); `id` is what feeds --report-channel.

## Risks
- None. Purely additive unwrapping; verified live against an org with 8 Slack
  channels — `channels list` now lists them and `--report-channel` round-trips
  into `checkin show`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ound

Aligns the CLI to the API team's report-channel hardening (commit 9324837):
channel validation on create/edit, names resolved on detail, and the documented
channels endpoint.

## Change Log
- display._print_attached_channels: render the resolved channel name as
  `#general` with platform, falling back to the raw id for legacy (unnamed)
  entries. Adds Channel + Platform columns to form/check-in detail.
- public_api_helpers: map the new `report_channel_not_found` code to a friendly
  message pointing at `dailybot channels list`.
- docs/API_REFERENCE: report_channels detail shape now carries name/platform;
  documented the `?name`/`?limit` query params on the channels endpoint.
- tests: +3 (name renders as #general, id fallback when unnamed, friendly
  error on a bogus channel).

## Verified live
- Bogus `--report-channel` → 400 report_channel_not_found → friendly CLI message.
- Valid channel → `form get` renders "#general (slack)"; name round-trips from
  the create response through detail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a config

A check-in only triggers for its participants, so a participant-less one is dead
config. The CLI now refuses to create empty check-ins and can fix existing ones.

## Change Log
- checkin create: if no --user/--team, an interactive terminal prompts to pick
  participants (default team suggested); a non-interactive run errors with
  "A check-in must have at least one participant." Never sends an empty set.
- checkin config: new --user/--team to replace participants; api_client
  update_checkin_config now forwards a `participants` body (verified live).
- authoring_helpers: prompt_participants_interactively (questionary checkbox of
  teams + people, default team pre-checked).
- tests: +4 (reject empty create, config forwards participants, client sends
  participants, create-with-team); updated 3 existing create tests to pass a team.
- docs: API_REFERENCE + checkin SKILL note the participant requirement and the
  new config flags.

## Risks
- checkin create now requires participants — intentional. Existing scripts that
  created empty check-ins will now get a clear error and must pass --user/--team.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The API team shipped Option A (explicit participants, no implicit default) with a
`checkin_requires_participant` 400. Our client guardrail already blocks empty
creates before the server; this maps the server code for the backstop paths
(direct API edge cases / other clients) to the same friendly guidance.

## Change Log
- public_api_helpers: map `checkin_requires_participant` → "A check-in must have
  at least one participant ... Add --user and/or --team."
- tests: +1 (server backstop error surfaces the friendly message).

## Verified
- create_checkin routes to /v1/checkins/create/ (the validated authoring
  endpoint, not the v2 ViewSet with legacy auto-assignment) — test at
  api_client_test.py already asserts the URL.
- Live: raw POST with empty participants → 400 checkin_requires_participant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The API team shipped the entire check-in config surface (frequency, reminders,
timezone mode, submission rules, privacy, intro/outro) on create + config, with
unknown-field rejection and per-field validation. This exposes all of it in the
CLI so an agent can configure a check-in exactly like the web UI.

## Change Log
- authoring_helpers.build_checkin_config: assemble a validated partial config
  dict from ~18 flags (enum + range checks mirroring the server contract).
- api_client: create_checkin / update_checkin_config accept a `config` dict
  merged inline into the request body.
- checkin create + config: shared `_config_flag_options` decorator adds
  --start-on/--end-on, --frequency/--every, --trigger-based, timezone mode,
  --reminders/--reminder-interval/--reminder-condition, --work-days,
  --allow-early/--allow-past/--allow-future, --anonymous, --privacy,
  --one-by-one, --intro/--outro, --report-time.
- display: checkin show now summarizes frequency, run span, reminders, options,
  and privacy in the panel.
- public_api_helpers: map unknown_field + the new invalid_* validation codes.
- tests: +19 (config builder validation, client merge, flag wiring, error maps,
  detail summary).
- docs: API_REFERENCE + checkin SKILL document the full flag set.

## Verified live
- `checkin config --reminders 3 --reminder-interval 30 --no-past --privacy
  everyone` applies and round-trips (previously the server silently dropped
  reminders — now fixed on their side and surfaced here).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(100% web parity)

## Summary
The API shipped the final "by-design-deferred" check-in fields. Align the CLI so
an agent can configure any check-in exactly like the web UI — nothing web-only left.

## Change Log
- build_checkin_config: added reminder_tone, is_smart_checkin,
  is_intelligence_enabled, max_clarifying_questions (0-5), frequency_advanced,
  frequency_cron (5-field), with fail-fast enum/range/field-count checks
- checkin create + config: new shared flags --reminder-tone, --smart/--no-smart,
  --intelligence/--no-intelligence, --max-clarifying, --frequency-advanced, --cron
- display: check-in panel now surfaces Advanced (cron), reminder tone, and an AI
  line (smart / intelligence / clarifying Qs)
- error mapping: invalid_reminder_tone, invalid_max_clarifying_questions,
  intelligence_requires_smart_checkin, invalid_frequency_cron,
  invalid_frequency_advanced → friendly messages
- docs: API_REFERENCE, checkin SKILL, README updated for the full-parity surface
- tests: +9 (config builder, flag forwarding, dependency-error mapping, panel render)

## Risks
- None for backward compat — all new flags are optional partial-update fields.
  AI dependency rules stay server-enforced (not approximated client-side) so a
  partial flip on an already-smart check-in isn't wrongly blocked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ency_advanced

## Summary
The API narrowed frequency_type to weekly (Option 2): monthly and custom cadences
are driven by frequency_advanced (+ frequency_cron for custom). Align the CLI so
--frequency rejects monthly/custom client-side and points users to the right flag.

## Change Log
- FREQUENCY_TYPES narrowed to ("weekly",) so build_checkin_config fails fast on
  monthly/custom instead of forwarding a value the server now rejects
- --frequency help + invalid_frequency_type message redirect to --frequency-advanced
- docs (API_REFERENCE, checkin SKILL) updated to "--frequency weekly (monthly/custom
  → --frequency-advanced)"
- tests: lock in that frequency_type=monthly is rejected; detail-render fixture uses
  the realistic weekly base + advanced custom

## Verification
Live-tested against a local org: --frequency monthly fails fast; monthly via
--frequency-advanced monthly and custom via --frequency-advanced custom --cron both
apply and round-trip on /detail/.

## Risks
- None for backward compat — weekly (the only real prior value) is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gic) + error mapping

## Summary
The API opened the question surface: short report titles, alternate phrasings, and
conditional/branching logic on both check-in and form questions. Wire the CLI to it
and map the new error codes. Question types stay the documented 4 (confirmed catalog).

## Change Log
- authoring_helpers: validate_short_question (<=512), build_variations (<=10,
  non-empty), validate_logic (rules/operators/actions/connectors + target types),
  build_question_logic (--logic-file or inline --jump-if-equals/--jump-to),
  resolve_question_extras, and a shared question_extras_options decorator
- build_question / build_question_edit_fields / parse_questions_file carry
  short_question, variations, logic
- checkin + form `questions add`/`edit` gain --short-question, --variation,
  --logic-file, --jump-if-equals, --jump-to
- display: question rows annotate report title / variation count / conditional logic
- error mapping: invalid_question_variations, invalid_question_logic,
  anonymous_irreversible (question_label_required was already mapped)
- docs: API_REFERENCE, checkin/forms SKILLs, README; fixed a stale README
  `--frequency custom` example (weekly-only)
- tests: +26 (extras builders, logic validation, file parsing, flag forwarding,
  display, error mapping)

## Verification
Live-tested against a local org: --short-question and --variation apply and
round-trip on /detail/; client-side limits fail fast. Question logic write shape is
blocked on a server contract gap (deployed serializer requires undocumented
question_key/prev_key ints) — reported separately; CLI implements the documented
contract and is ready once the server matches it.

## Risks
- None for backward compat — all new flags are optional.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… jumps, full operator set

## Summary
The API made logic navigation keys server-computed, so the documented {rules: {...}}
shape now works. Live testing surfaced three real rules: rules_else is required, jump
targets are forward-only, and boolean comparisons are JSON true/false. Align the CLI.

## Change Log
- build_question_logic: inline shortcut now emits the required rules_else (new
  --else-jump-to flag, default -1 = end) and coerces --jump-if-equals true/false to a
  JSON boolean (what the server needs for boolean questions)
- validate_logic: require a rules_else fallback action (fail fast, matching the server)
- LOGIC_OPERATORS widened to the full documented union across question types
  (begins_with/ends_with/numeric comparators); the server enforces per-type legality
- error mapping: stop masking invalid_question_logic so the server's detail (which
  names the bad operator and lists the valid ones for the type) reaches the user
- docs: API_REFERENCE documents the per-type operators, required rules_else,
  forward-only targets, and server-computed navigation keys
- tests: +6 (rules_else required, boolean coercion, else target, extended operator)

## Verification
Live-tested against a local org: inline logic on boolean (true) and text questions
and --logic-file all apply and round-trip on /detail/; missing rules_else fails fast
client-side; an undeployed operator surfaces the server's own valid-list message.

## Risks
- None for backward compat — logic flags are optional; the wider operator set is
  validated authoritatively server-side.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ffix)

## Summary
The deployed logic engine spells the numeric comparison operators with a `_than`
suffix, not `_to`. Align the CLI's operator whitelist and docs so valid numeric
comparators aren't wrongly rejected client-side.

## Change Log
- LOGIC_OPERATORS: lower_or_equal_to → lower_or_equal_than,
  greater_or_equal_to → greater_or_equal_than
- API_REFERENCE: same correction in the per-type operator list

## Verification
Live-tested against a local org (extended operators now deployed): begins_with on a
text question and greater_or_equal_than on a numeric question both apply; delete now
auto-clamps dangling forward-jump targets to -1 instead of failing.

## Risks
- None — corrects two operator spellings to match the server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ipant

## Summary
Passing a --user/--team that doesn't resolve (e.g. an email, a typo) crashed
`checkin create`/`config` with an uncaught ValueError traceback from the shared
resolver. Translate it to a friendly AuthoringError like every other command.

## Change Log
- parse_participants: wrap the resolver calls and re-raise ValueError as
  AuthoringError (renders via print_error to stderr, exits non-zero)
- test: unknown participant raises AuthoringError, not a traceback

## Verification
Live-tested: `checkin create --user nobody@example.com` now prints
`Error: No user found matching "nobody@example.com".` instead of a stacktrace.
Full end-to-end re-verified against a local org (create + config + questions with
extras + logic on check-ins and forms).

## Risks
- None — pure error-path hardening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hort-question

## Summary
AI report-title generation is a frontend UX convenience — and, when intelligence is
on, an async job overwrites client titles. So from the CLI, treat short_question as
effectively mandatory when authoring questions: require it, or make the caller opt
into AI generation explicitly.

## Change Log
- New --ai-short-question flag on `questions add` and `create` (checkin + form)
- require_short_question / require_short_questions helpers enforce a report title on
  single add and on every seeded question in a bulk create (naming the offenders),
  skipped only when --ai-short-question is set
- interactive builder prompts for the report title per question (re-asks on blank)
  unless --ai-short-question
- docs: API_REFERENCE, README, checkin/forms SKILLs note the requirement + opt-out
- tests: +8 (helper unit tests, add/create rejection, ai opt-in, interactive prompt,
  updated existing fixtures to supply a title or opt in)

## Verification
Live-tested against a local org: add/create without a title now fails fast with a
clear message (bulk names the offending question); --short-question and
--ai-short-question both succeed.

## Risks
- Behavior change: authoring a question now requires --short-question or
  --ai-short-question. Intentional per product direction; edit is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rt_question_required

## Summary
The API now validates that a report title is present on create/add (unless opted
in) and preserves explicit titles from the AI job. Wire the CLI's --ai-short-question
to the server's `generate_short_question` opt-in and map the new error code.

## Change Log
- api_client.create_checkin / create_form: new generate_short_question param sent
  as a top-level request field when True
- checkin/form create: forward generate_short_question=ai_short_question
- checkin/form questions add: set generate_short_question on the question payload
  when --ai-short-question is passed
- map short_question_required -> friendly message (suggests --short-question /
  --ai-short-question)
- tests: +5 (client sends/omits the field, ai opt-in forwarded, error mapping)

## Verification
Live-tested against a local org: server now returns 400 short_question_required for
a titleless question without opt-in; --ai-short-question sends the opt-in and the
create succeeds. Explicit titles are preserved by the AI job on the create path
(add-single preservation is still pending server-side; reported separately).

## Risks
- None — additive field, only sent when opted in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oval, command

## Summary
The API brought form create/config to web parity (workflow states, three permission
audiences, anonymous/public/approval settings, ChatOps command; unknown-field
rejection). Add the CLI surface: a new `form config` command + config flags on
`form create`, mirroring `checkin config`.

## Change Log
- authoring_helpers: build_form_config, parse_workflow_states, build_workflow,
  build_form_audience (name/UUID resolution), validate_command, and resolve_form_config
  orchestrator; new constants (FORM_PERMISSION_MODES, WORKFLOW_MAX_STATES, patterns)
- api_client: create_form / update_form_config accept a `config` dict merged inline
- form.py: shared _form_config_flag_options decorator; new `form config` command;
  config flags added to `form create` (--state, --can-edit/see/change-states,
  --anonymous/public/brand/require-identity, --approval/--approver-*, --command, etc.)
- display: print_form_detail rewritten for the canonical nested shape — renders
  workflow states, permission audiences, anonymous/public/approval, and command
- error mapping: workflow_requires_states, invalid_workflow_state,
  invalid_permission_audience, invalid_approvers, invalid_command,
  command_already_exists, form_name_too_short
- docs: API_REFERENCE, README, forms SKILL
- tests: +30 (config builder, workflow/audience/command helpers, create/config flag
  forwarding, validations, error mapping, client config merge, detail render)

## Verification
Live-tested against a local org: full-config create round-trips (workflow, anonymous,
public, identity, command, permissions); `form config` applies partial updates
(restricted audience with team resolution, --no-workflow, --no-command); client-side
validations fail fast (bad color, restricted without who, bad command charset).

## Risks
- None for backward compat — `form edit` unchanged; all new flags optional.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
xergioalex and others added 5 commits July 6, 2026 01:48
## Summary
reorder_form_questions and reorder_checkin_questions sent {"order": [...]}, but the
server expects {"question_uuids": [...]}. The unknown "order" field was silently
ignored and the endpoint returned 200 with the unchanged list, so the CLI reported
"reordered" while nothing actually moved. Send the correct field name.

## Change Log
- api_client: reorder_form_questions / reorder_checkin_questions now send
  {"question_uuids": order}
- tests: updated the two reorder payload assertions

## Verification
Live-tested against a local org: reordering form and check-in questions now actually
changes the stored order (previously a silent no-op).

## Risks
- None — corrects the request field so reorder finally takes effect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lace audiences

## Summary
The API hardened the reorder endpoints (reject unknown/missing/incomplete/duplicate
payloads) and confirmed full-replace semantics for form approvers/permission
audiences. Map the new error codes and send audiences/approvers as complete objects.

## Change Log
- error mapping: question_uuids_required, question_uuids_incomplete,
  question_uuids_duplicate (unknown_field / question_not_found already mapped)
- build_form_audience / resolve_form_config approvers: emit both user_uuids and
  team_uuids explicitly (empty where unset) so an edit is an unambiguous replace,
  matching the server's Option A semantics and report_channels
- tests: reorder incomplete-set error mapping; audience assertions updated to the
  explicit both-keys shape

## Verification
Live-tested against a local org: reorder now rejects a wrong field ({order} ->
unknown_field) and an incomplete set (question_uuids_incomplete), and applies a full
valid set; setting a restricted audience to a user clears the previously-set team
(clean replace).

## Risks
- None — additive error mappings; the explicit both-keys payload is semantically
  identical to before under the server's replace rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…l cap

## Summary
The API now echoes a form's public share URL and enforces a 3 report-channel cap.
Render the URL and fail fast client-side on too many channels.

## Change Log
- display: form panel + create/update summary show public_url when present
- authoring_helpers: MAX_REPORT_CHANNELS=3 + check_report_channels(); called on
  form create/edit/config and checkin create/config
- error mapping: too_many_report_channels
- tests: +3 (channel cap fail-fast, public_url shown after config, cap on form config)

## Verification
Live-tested: public_url renders after `form config --public` and in `form get`;
4 channels fail fast client-side ("limit is 3") and the server rejects them too
(too_many_report_channels).

## Risks
- None — additive rendering + a fail-fast that mirrors the server cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… approvers

## Summary
Two CLI ergonomics improvements: the user resolver now matches an email (in
addition to name/UUID), and forms gain --no-approvers to clear the approver list.

## Change Log
- resolve_user_by_name_or_uuid: exact email match when the identifier contains "@"
  (falls back to a clear "no user with email" error)
- form config/create: --no-approvers sends approvers {user_uuids:[], team_uuids:[]}
  (conflicts with --approver-user/-team)
- help text: --user / --approver-user mention email
- tests: +5 (email resolution, no-approvers clear + conflict, email approver forwarding)

## Verification
Live-tested: --no-approvers clears the list. NOTE: email resolution is functional
client-side but the current /v1/users/ directory does not return an `email` field,
so email lookups can't match until the API adds it (raised separately) — the code is
correct and future-proof (unit-tested against a directory that includes email).

## Risks
- None — additive; name/UUID resolution unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…manager)

## Summary
Email is already available on /v1/users/ behind ?include_email=true (server-gated to
admins/managers). Request it when resolving participants so --user/--approver-user/
--can-*-user accept an email.

## Change Log
- api_client.list_users: include_email flag adds ?include_email=true
- parse_participants: fetches the directory with include_email=True
- resolver: clearer message when email lookup isn't available (member token —
  directory has no emails): points to name/UUID instead
- tests: list_users include_email query assertion

## Verification
Live-tested with an admin token: --approver-user and check-in --user now resolve a
person by email end-to-end; a member token falls back to a clear "needs
admin/manager permissions" message.

## Risks
- None — include_email is silently ignored for non-privileged callers; name/UUID
  resolution unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@xergioalex xergioalex merged commit 56fd766 into main Jul 6, 2026
4 checks passed
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