You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status: accepted and committed locally — exact accepted commit 9d204d208820e3d842a3d3fc83493c230bcadaa5; not merged, pushed, deployed, shipped, or closed
Tags: enhancement, portal, frontend, testing, design, P1
Parent: #162 Wave A slice 2
Depends on: satisfied — accepted #218 commit 0c89588df809b2e84af02e796d1910a25eea0165, accepted #180 behavior foundation, and accepted #161 shell/Home foundation
Blocks: #162 integrated Wave A acceptance
Next owner: Orchestrator — when coordinated publication resumes, merge the accepted local Wave A chain in order, push main, then hand off to On-Call; no implementation or review rerun is pending for #219
Resume condition: local main is clean and the Orchestrator is ready to publish the accepted Wave A chain; #219 requires no rerun unless commit 9d204d208820e3d842a3d3fc83493c230bcadaa5 changes
Product outcome
Templates and Recurring feel like one safe operator workflow without changing their domain contracts:
Templates remain read-only projections of reviewed Git-authored definitions. Operators can search, inspect source/revision and Task definitions, create a Card, and explicitly review/apply Template updates to selected existing Cards.
Recurring remains the place to create and edit schedules that generate Tasks, clearly distinguish Active from Paused, and safely pause, resume, or delete a schedule.
Editing a recurring schedule makes clean, changed, saving, validation, conflict, retry, and discard consequences explicit. A dismissal never silently loses changed values.
On a phone, one schedule is readable before secondary actions; its Edit/Pause-or-Resume/Delete controls are available through an accessible row-owned disclosure instead of a dense three-button strip.
Failed Template batch preview/apply and partial conflicts stay in the selected Template detail, announce the failure, preserve the reviewed selection/result context, and offer the next safe recovery action.
This is gap-only convergence over the canonical frontend. It does not create a Template editor, change Template/Card/Task semantics, alter recurring generation, or introduce a new API, data model, router, shell, or compatibility layer.
PM amendment — exact implementation blockers
The Software Engineer blocker report is substantiated against the accepted #218 containing baseline, the #159 durable evidence contract, and accepted held #164 commit 3e835a19017da18f2177d81fb7e084764970dee3. This amendment changes no product outcome, runtime/API contract, or production write boundary.
Authorize backend/scripts/frontend-capabilities.test.mjs only to add the five already-groomed durable state suffixes to the existing Templates/Recurring expected-state lists and add exact admin role overrides for templates.batch-failure, recurring.editor-dirty, recurring.validation, recurring.saving, and recurring.conflict. Do not alter schema, collector, reporter, accepted evidence type, role semantics, route/API inventories, or any unrelated state.
Authorize backend/e2e/issue-218-shared-primitives.spec.js only for one minimal mobile interaction that opens the row-owned “Schedule actions” disclosure before the existing Delete action. Preserve Converge Wave A surfaces on bounded shared UI primitives #218’s fixture, assertions, screenshot inventory, capability claims, and all other journey behavior.
Correct the focused Playwright recipe to execute from backend/ with backend/playwright.config.js, so the configured server/base URL/workers apply.
Authorized refreeze sequence: make only the two newly authorized test/evidence edits; retain the seven existing bounded candidate paths; rerun focused frontend tests, corrected focused Playwright, the full browser suite with all 147 states, frontend parity, backend test/typecheck/build, SAM validation/build and artifact checks, make ci, and diff integrity; regenerate and inspect exactly the 12 issue screenshots; post new diff/status/content fingerprints; then repeat Designer, independent Tester, and PM review on that exact fingerprint. Earlier partial green runs are supporting diagnostics, not lifecycle verdicts.
Frozen baseline and dependency reconciliation
The PM inspected source and tests read-only at clean baseline 78e91223203aa54376a318fd1a3214ce0242e0c3.
canonical Git-authored Template projection and recurring API behavior.
Accepted #218 commit 0c89588df809b2e84af02e796d1910a25eea0165 converges shared headers, action rows, forms, semantic statuses, honest states, and responsive rules and is the exact containing baseline for #219. The Software Engineer posted the required refreshed inventory before editing. #219 consumes those accepted primitives and must not revert, duplicate, absorb, or restyle them. If a later accepted integration changes an owned path before #219 freezes, reconstruct the candidate and repeat Designer, Tester, and PM review on the new fingerprint.
Held #158/#164 branches are not part of baseline 78e9122. If either is integrated first, preserve its accepted behavior and rerun the overlap inventory; do not resolve overlap by reverting or silently rewriting it.
Criterion-to-current-source/test inventory
Already compliant — preserve, do not rebuild
Canonical Template/Card/Task contract
frontend/src/surfaces/tasks/templates.js renders a searchable, deep-linkable, read-only Git-authored Template list/detail with source path, revision, Task definitions, Create card, stale/not-found recovery, and intentional mobile list/detail return.
Template definitions have no browser editor or Save/Delete action. backend/e2e/canonical-capability-behavior.spec.js proves POST/PUT/DELETE return 405 and both operator/admin roles inspect the same projection.
Existing Card update behavior is explicit preview → checkbox selection → apply. Nothing is selected automatically; partial results identify applied Cards and conflicts without silent retry.
backend/e2e/card-template-updates.spec.js, frontend/test/tasks-surface.test.mjs, and durable states templates.read-only, templates.source-revision, templates.create-card, templates.reviewed-card-batch, templates.method-not-allowed, templates.failure, and templates.stale-not-found cover the canonical contract.
There is no “dirty Template editor” to build. Clean/dirty/saving/validation/conflict editor criteria in this issue apply to the recurring schedule editor. Template mutation remains deployment-owned and read-only in the portal.
Accepted Recurring semantics
frontend/src/surfaces/tasks/recurring.js exposes Active/Paused as real text without prohibited ARIA, renders honest unavailable/empty/ready summaries, and retains row identity across mutation recovery.
Pause and Resume use the same authoritative PUT contract, disable only the initiating control while pending, reload server state, retain the schedule on failure, announce row-owned recovery, focus it, and leave the same action available for retry.
Delete uses a destructive confirmation that states only the schedule is removed and generated Tasks remain. A referenced 409 retains the row and directs the operator to Pause; an unrelated failure remains retryable.
frontend/src/surfaces/tasks/quick-create.js already provides labeled recurring create/edit fields, cadence preview, five-field cron validation, duplicate-submit prevention, aria-busy saving text, assertive failure/conflict feedback, retained values, and authoritative reload when Cancel follows a 409.
Unit coverage in frontend/test/tasks-surface.test.mjs proves create/edit payloads, dialog naming/focus trap, validation mechanics, conflict Cancel reload, stale-route completion, failed pause focus, protected delete, and Active/Paused semantics.
Real-server journeys in backend/e2e/canonical-capability-behavior.spec.js and backend/e2e/canonical-route-parity.spec.js prove empty/ready, persisted pause/resume, role denial, retryable 503, removable delete, referenced 409 guidance, mobile rendering, accessibility, and route behavior.
Existing durable states are recurring.empty, recurring.ready, recurring.pause, recurring.resume, recurring.delete-unreferenced, recurring.delete-referenced-409, recurring.permission-denied, and recurring.failure.
These accepted #180 semantics are invariants, not implementation work.
Recurring drafts can be discarded silently.createQuickFormOverlay() closes immediately from Close, backdrop, or Escape. The recurring editor has no baseline snapshot, clean/dirty state, changed-state announcement, or discard confirmation. A changed create/edit draft can therefore disappear without an explicit decision.
Recurring mobile rows expose a dense action strip. At phone width the current CSS lays Edit, Pause/Resume, and Delete into three equal columns. There is no row-owned disclosure with an accessible expanded state, keyboard operation, or stable focus after rerender.
Template batch request failures use non-error feedback semantics.runtime-template-batch-message always has role="status"; preview/apply request failures and partial conflict recovery do not move focus to an assertive, selected-Template-owned message. Recovery copy exists but is not one coherent announced failure contract.
Durable evidence does not identify the editor lifecycle. The capability catalog has no exact runtime states for recurring changed draft, validation, saving, or conflict, and no exact Template batch request-failure state. Existing screenshots/source assertions cannot substitute for passed same-run browser evidence.
backend/e2e/issue-219-templates-recurring.spec.js — one dedicated real-server behavior spec
backend/e2e/frontend-capabilities.json — only the exact new behavior states below
backend/scripts/frontend-capabilities.test.mjs — only the matching expected-state entries and exact admin role overrides for those five IDs
backend/e2e/issue-218-shared-primitives.spec.js — only one mobile “Schedule actions” disclosure-opening step before its existing Delete action
Existing backend/e2e/card-template-updates.spec.js, backend/e2e/canonical-capability-behavior.spec.js, or backend/e2e/canonical-route-parity.spec.js only if the post-Converge Wave A surfaces on bounded shared UI primitives #218 inventory proves a minimal pointer/fixture adjustment is required; no journey rewrite or ownership transfer
Add only these durable state identities if still absent after #218:
templates.batch-failure
recurring.editor-dirty
recurring.validation
recurring.saving
recurring.conflict
Do not edit backend runtime/routes/tests beyond the two exact test/evidence exceptions above, API schemas, seed contracts, #159 schema/collector/reporter code, shell/runtime/Home/account/team files, or unrelated styles. Any newly required production path or backend contract requires another PM amendment before editing.
Acceptance criteria
Gap-only implementation
Before editing, the engineer posts the exact starting SHA plus a criterion-to-current-source/test inventory classifying every item as already compliant, concrete gap, Converge Wave A surfaces on bounded shared UI primitives #218/dependency-owned, or out of scope.
A newly opened create/edit form is programmatically clean. Changing any persisted field makes it dirty; returning every persisted field to its baseline makes it clean again.
Dirty state is communicated in concise visible text and a polite live state without changing the dialog title or pretending a save occurred.
Clean Cancel, Close, backdrop, or Escape closes normally and restores focus to the connected opener.
Dirty Cancel, Close, backdrop, or Escape opens one accessible discard confirmation that names the recurring schedule/draft. Keep editing returns to the same dialog, exact values, and useful field focus; Discard closes and restores focus to the opener.
While saving, one submit causes at most one POST/PUT, submit is busy/disabled, dismissal cannot produce an ambiguous second mutation, and the pending state is announced.
Validation keeps all entered values, associates errors to exact fields, focuses the first invalid field, and performs no request.
A 409 keeps all entered values and dirty state, announces that server state changed, and offers exactly two safe choices: keep editing/retry with the current draft, or discard and reload authoritative schedules.
A non-409 failure keeps values and dirty state, stays retryable, and never reports success. Successful save closes only after authoritative success and reloads without replacing a newer route.
Recurring list and mobile disclosure
Desktop 1440×900 retains a readable schedule row with human description, Active/Paused text, cadence, next run or paused consequence, safe assignee label, and the existing state-valid actions.
At 390×844, each schedule presents its identity/status/facts before one at-least-44×44 “Schedule actions” disclosure. Edit, Pause-or-Resume, and Delete appear in reading order only inside that row-owned disclosure; destructive Delete remains visually and semantically separated.
Disclosure expanded/collapsed state is programmatically exposed, keyboard operable, and not inferred from an icon. Opening one row does not change another schedule.
Pause/resume/delete success rerenders authoritative state and restores focus to the same surviving schedule/action context. Failure retains the expanded row, announces row-owned guidance, and focuses the recovery message/control.
Referenced-delete 409 leaves the schedule visible and expanded, names Pause as the safe alternative, and states generated Tasks and notifications are preserved.
Loading/unavailable never renders false zero counts; empty explains that New schedule creates the first schedule; a failed source remains unavailable with retry.
Template list/detail and batch recovery
Templates remain searchable and deep-linkable with a readable desktop list/detail and intentional mobile one-pane detail plus canonical Back/Forward/return behavior.
At 390×844 the selected Template detail, Back control, Create card action, definition, Tasks, and Card-update region remain reachable with 44×44 controls, no page-level horizontal scroll, clipping, overlap, or hidden recovery.
Batch preview/apply pending state identifies the selected Template and prevents duplicate submission without clearing explicit Card selections.
Preview/apply request failure is an assertive selected-Template-owned error, preserves the selected Template and usable context, receives useful focus after final render, and exposes one precisely named retry.
Partial apply reports each applied Card and each conflict separately, never retries a conflict silently, and requires a fresh preview before a conflicted Card can be selected again.
Routine operator copy uses human Template/Card/Task labels and does not expose raw IDs, internal tokens, private repository paths beyond the accepted public-safe projection, or provider/storage metadata.
Accessibility, responsive, and honest state
Changed states retain one main/page-heading contract, nested headings, native labels/list/dialog/disclosure semantics, visible focus, logical keyboard order, focus containment/restoration, and text/programmatic status meaning.
At 1440×900 there is one dominant decision region; at 390×844 fields are one column, every control is at least 44×44 CSS pixels, and there is no page-level horizontal scroll, clipping, overlap, or unreachable action.
Light/dark tokens preserve hierarchy and semantic contrast. Reduced motion removes no state or focus cue. Zoom/reflow remains usable.
Automated scans report zero critical or serious WCAG A/AA findings on every captured changed state.
Synthetic fixtures, screenshots, logs, and issue evidence contain no operational corpus, real person/contact/provider data, private links, credentials, production identifiers, finance/sponsor facts, or generated operational artifacts.
Durable real-server behavior and parity
Focused production-module tests cover clean↔dirty reversibility, every dismissal path, discard confirmation, duplicate-submit prevention, validation, 409/non-409 retention, mobile disclosure isolation, rerender focus, and Template batch error recovery.
The normal local TypeScript server and persisted synthetic records drive the dedicated Playwright journey. Core behavior uses no request interception, fixed sleep, retry-as-synchronization, source-string assertion, incidental copy/whitespace pin, broad 404 swallowing, history-length arithmetic, test-order dependence, screenshot assertion, or pixel/byte golden.
The successful full browser run emits same-run passing evidence for every existing Templates/Recurring state and the exact new states retained after post-Converge Wave A surfaces on bounded shared UI primitives #218 inventory, for every required role.
Source, backend/dist, and packaged SAM frontend assets are identical for every changed asset; the normal source/SAM parity run accounts for every evidence record and proves the same route/state behavior.
Screenshots are visual evidence only. They do not count as behavior, capability, accessibility, or parity proof.
Test scenarios
Dirty recurring draft dismissal
Given a clean edit dialog for a synthetic recurring schedule
When the operator changes description, cadence, assignee, or Active and attempts Close, Cancel, backdrop dismissal, or Escape
Then a discard confirmation appears without losing values
When Keep editing is selected
Then the same values and useful focus remain
When every field is restored to baseline or Discard is selected
Then the dialog closes through the clean/explicit path and focus returns to the connected opener
Validation, saving, conflict, and retry
Given a dirty recurring draft
When required description or cron is invalid
Then exact fields are announced/focused and no request occurs
When a valid draft is submitted twice while the first request is pending
Then one mutation occurs and saving is announced
When the server returns 409 or 503
Then values and dirty state remain, false success never appears, and the corresponding reload/discard or retry path is explicit
Mobile schedule actions and protected delete
Given active, paused, removable, and referenced synthetic schedules at 390×844
When each row disclosure is operated by keyboard/touch
Then only that row exposes Edit, Pause/Resume, and Delete in reading order
When referenced Delete returns authoritative 409
Then the same row remains expanded, generated work is preserved, and Pause guidance is announced and focused
Template batch failure and partial conflict
Given one read-only Template with multiple existing synthetic Cards
When preview fails, succeeds, selected Cards are applied, and one Card conflicts
Then the selected Template and explicit selections/results remain understandable, request failure is assertive/retryable, applied and conflicted Cards are distinct, and the conflict requires a fresh preview without silent retry
Route, responsive, and source/SAM identity
Given direct Templates and Recurring routes on source and clean packaged SAM servers
When the operator searches/selects a Template, uses mobile Back/Forward, opens recurring row actions, edits/discards/saves, and reloads
Then URL/entity/focus and authoritative state agree at 1440×900 and 390×844, and every changed frontend asset and durable evidence record matches across source and SAM
Synthetic screenshot inventory
Capture exactly these 12 untracked native-size PNGs under .tmp/screenshots/issue-219/; delete stale extras before review:
Source/SAM pairs use identical synthetic fixtures and show the same route, selected entity, expanded/dirty/conflict state, accessible-name summary, and console/page-error result. Designer and Tester inspect every image at native resolution for hierarchy, state/copy ownership, theme/contrast, touch target sizing, overflow, clipping, overlap, first-decision visibility, and public safety. Do not commit, publish, or attach these images to the public issue.
Exact verification
Engineer may run focused tests while iterating. make test-sam-workspace-isolation is explicitly excluded for this containing baseline under the PM amendment; do not edit its verifier in #219. Independent Tester runs the complete workflow on one frozen diff/status/content fingerprint and records each command, exit code, observed counts, changed behavior titles, capability-state accounting, and evidence paths:
node --test frontend/test/tasks-surface.test.mjs
npm run test:frontend:unit
npm run test:frontend:coverage
npm --prefix backend test
npm --prefix backend run typecheck
npm --prefix backend run build
node backend/scripts/verify-frontend-artifact.mjs --source frontend --artifact backend/dist
cd backend && npx playwright test e2e/issue-219-templates-recurring.spec.js e2e/card-template-updates.spec.js e2e/canonical-capability-behavior.spec.js e2e/canonical-route-parity.spec.js
npm --prefix backend run test:e2e
npm --prefix backend run test:e2e:frontend-parity
make sam-validate
make sam-build
node backend/scripts/verify-frontend-artifact.mjs --source frontend --artifact .aws-sam/build/BackendFunction
make ci
git diff --check
The dedicated #219 spec must run inside the normal full Playwright workflow and use its normal capability collector. Do not run raw import/export/migration/restore/data-movement tools, provider actions, AWS commands beyond local SAM validation/build, workflow dispatch, manual deploy, or production/private data checks.
Lifecycle gates
PM baseline inventory completed read-only at 78e9122
Reviewed containing SHA 0c89588df809b2e84af02e796d1910a25eea0165 and project-local isolated writer order recorded
Software Engineer posted refreshed criterion/source/test inventory before editing
Software Engineer applies the two PM-authorized test/evidence adjustments, reruns the corrected complete gate, and posts new frozen diff/status/content fingerprints plus READY FOR DESIGN/TEST
Designer inspects exactly 12 screenshots and posts DESIGN PASS on that fingerprint
Independent Tester verifies every criterion and posts TESTER PASS on the same fingerprint
PM performs operator-perspective acceptance and posts ACCEPTED on the same fingerprint
No HUMAN gate is required for this local, synthetic, provider-free slice.
No-backcompat boundary
Make the final behavior atomic. Remove superseded #219-owned markup/selectors/tests in the same change. Do not add aliases, legacy fallbacks, hidden old controls beside new disclosure controls, dual event paths, old/new state readers, temporary feature flags, or version branches. If the accepted #218 primitive cannot express the required behavior, stop for PM amendment instead of creating a parallel primitive.
Explicit exclusions
A Template editor or Template POST/PUT/DELETE; editing YAML, private knowledge, or source repositories.
Any change to canonical Template/Card/Task contracts, Card instantiation, Card lifecycle, recurring cron/generation semantics, permission policy, persisted fields, APIs, backend routes, DynamoDB, migrations, imports, restores, exports, or infrastructure.
Broad CSS rewrite, stylesheet splitting, framework/component library, router/runtime abstraction, second frontend, or new token vocabulary.
Provider calls, production writes, AWS deployment, manual deploy, workflow dispatch, real external accounts, or HUMAN gates.
Raw operational knowledge, private links/data, real identifiers, tracked screenshots, screenshot goldens, generated design boards, or public screenshot attachments.
Converge Templates and Recurring operator flows
Status: accepted and committed locally — exact accepted commit 9d204d208820e3d842a3d3fc83493c230bcadaa5; not merged, pushed, deployed, shipped, or closed
Tags:
enhancement,portal,frontend,testing,design,P1Parent: #162 Wave A slice 2
Depends on: satisfied — accepted #218 commit 0c89588df809b2e84af02e796d1910a25eea0165, accepted #180 behavior foundation, and accepted #161 shell/Home foundation
Blocks: #162 integrated Wave A acceptance
Next owner: Orchestrator — when coordinated publication resumes, merge the accepted local Wave A chain in order, push main, then hand off to On-Call; no implementation or review rerun is pending for #219
Resume condition: local main is clean and the Orchestrator is ready to publish the accepted Wave A chain; #219 requires no rerun unless commit 9d204d208820e3d842a3d3fc83493c230bcadaa5 changes
Product outcome
Templates and Recurring feel like one safe operator workflow without changing their domain contracts:
This is gap-only convergence over the canonical frontend. It does not create a Template editor, change Template/Card/Task semantics, alter recurring generation, or introduce a new API, data model, router, shell, or compatibility layer.
PM amendment — exact implementation blockers
The Software Engineer blocker report is substantiated against the accepted #218 containing baseline, the #159 durable evidence contract, and accepted held #164 commit
3e835a19017da18f2177d81fb7e084764970dee3. This amendment changes no product outcome, runtime/API contract, or production write boundary.backend/scripts/frontend-capabilities.test.mjsonly to add the five already-groomed durable state suffixes to the existing Templates/Recurring expected-state lists and add exact admin role overrides fortemplates.batch-failure,recurring.editor-dirty,recurring.validation,recurring.saving, andrecurring.conflict. Do not alter schema, collector, reporter, accepted evidence type, role semantics, route/API inventories, or any unrelated state.backend/e2e/issue-218-shared-primitives.spec.jsonly for one minimal mobile interaction that opens the row-owned “Schedule actions” disclosure before the existing Delete action. Preserve Converge Wave A surfaces on bounded shared UI primitives #218’s fixture, assertions, screenshot inventory, capability claims, and all other journey behavior.backend/withbackend/playwright.config.js, so the configured server/base URL/workers apply.make test-sam-workspace-isolationfrom Converge Templates and Recurring operator flows #219. Its unchanged containing-baseline dependency-location failure is unrelated to Converge Templates and Recurring operator flows #219 and is already repaired, fully verified, PM-accepted, and committed in held Show signed-in identity and authorized teammates’ Task/Card work #164. Converge Templates and Recurring operator flows #219 must not duplicate or cherry-pick that repair. Normal SAM validation/build, source/build/SAM artifact identity, packaged runtime/frontend isolation exercised bymake ci, and source/SAM browser parity remain mandatory.Authorized refreeze sequence: make only the two newly authorized test/evidence edits; retain the seven existing bounded candidate paths; rerun focused frontend tests, corrected focused Playwright, the full browser suite with all 147 states, frontend parity, backend test/typecheck/build, SAM validation/build and artifact checks,
make ci, and diff integrity; regenerate and inspect exactly the 12 issue screenshots; post new diff/status/content fingerprints; then repeat Designer, independent Tester, and PM review on that exact fingerprint. Earlier partial green runs are supporting diagnostics, not lifecycle verdicts.Frozen baseline and dependency reconciliation
The PM inspected source and tests read-only at clean baseline
78e91223203aa54376a318fd1a3214ce0242e0c3.That baseline contains:
e684162andb045739, including Recurring Active/Paused programmatic text, route-fresh mutation handling, row-owned pause failure/retry, deterministic real-browser behavior, and accessibility-race repairs;7d77632and64476d2; Converge Templates and Recurring operator flows #219 neither changes nor revalidates Home;Accepted #218 commit
0c89588df809b2e84af02e796d1910a25eea0165converges shared headers, action rows, forms, semantic statuses, honest states, and responsive rules and is the exact containing baseline for #219. The Software Engineer posted the required refreshed inventory before editing. #219 consumes those accepted primitives and must not revert, duplicate, absorb, or restyle them. If a later accepted integration changes an owned path before #219 freezes, reconstruct the candidate and repeat Designer, Tester, and PM review on the new fingerprint.Held #158/#164 branches are not part of baseline
78e9122. If either is integrated first, preserve its accepted behavior and rerun the overlap inventory; do not resolve overlap by reverting or silently rewriting it.Criterion-to-current-source/test inventory
Already compliant — preserve, do not rebuild
Canonical Template/Card/Task contract
frontend/src/surfaces/tasks/templates.jsrenders a searchable, deep-linkable, read-only Git-authored Template list/detail with source path, revision, Task definitions, Create card, stale/not-found recovery, and intentional mobile list/detail return.backend/e2e/canonical-capability-behavior.spec.jsproves POST/PUT/DELETE return 405 and both operator/admin roles inspect the same projection.backend/e2e/card-template-updates.spec.js,frontend/test/tasks-surface.test.mjs, and durable statestemplates.read-only,templates.source-revision,templates.create-card,templates.reviewed-card-batch,templates.method-not-allowed,templates.failure, andtemplates.stale-not-foundcover the canonical contract.There is no “dirty Template editor” to build. Clean/dirty/saving/validation/conflict editor criteria in this issue apply to the recurring schedule editor. Template mutation remains deployment-owned and read-only in the portal.
Accepted Recurring semantics
frontend/src/surfaces/tasks/recurring.jsexposes Active/Paused as real text without prohibited ARIA, renders honest unavailable/empty/ready summaries, and retains row identity across mutation recovery.frontend/src/surfaces/tasks/quick-create.jsalready provides labeled recurring create/edit fields, cadence preview, five-field cron validation, duplicate-submit prevention,aria-busysaving text, assertive failure/conflict feedback, retained values, and authoritative reload when Cancel follows a 409.frontend/test/tasks-surface.test.mjsproves create/edit payloads, dialog naming/focus trap, validation mechanics, conflict Cancel reload, stale-route completion, failed pause focus, protected delete, and Active/Paused semantics.backend/e2e/canonical-capability-behavior.spec.jsandbackend/e2e/canonical-route-parity.spec.jsprove empty/ready, persisted pause/resume, role denial, retryable 503, removable delete, referenced 409 guidance, mobile rendering, accessibility, and route behavior.recurring.empty,recurring.ready,recurring.pause,recurring.resume,recurring.delete-unreferenced,recurring.delete-referenced-409,recurring.permission-denied, andrecurring.failure.These accepted #180 semantics are invariants, not implementation work.
Concrete unmet gaps owned by #219
createQuickFormOverlay()closes immediately from Close, backdrop, or Escape. The recurring editor has no baseline snapshot, clean/dirty state, changed-state announcement, or discard confirmation. A changed create/edit draft can therefore disappear without an explicit decision.runtime-template-batch-messagealways hasrole="status"; preview/apply request failures and partial conflict recovery do not move focus to an assertive, selected-Template-owned message. Recovery copy exists but is not one coherent announced failure contract.#218-owned or dependency-owned — preserve exactly
Bounded write ownership
After the required post-#218 inventory, implementation may edit only:
Production
frontend/src/surfaces/tasks/quick-create.js— recurring-form dirty/discard lifecycle only; shared Task/Card quick forms must remain behaviorally unchanged.frontend/src/surfaces/tasks/recurring.js— mobile row disclosure and row-owned action/focus behavior only.frontend/src/surfaces/tasks/templates.js— Template batch failure/partial-conflict announcement and recovery only.frontend/src/styles.css— minimal Converge Templates and Recurring operator flows #219 layout/disclosure states consuming Converge Wave A surfaces on bounded shared UI primitives #218 primitives; no duplicate primitive declarations.Tests and durable evidence
frontend/test/tasks-surface.test.mjsbackend/e2e/issue-219-templates-recurring.spec.js— one dedicated real-server behavior specbackend/e2e/frontend-capabilities.json— only the exact new behavior states belowbackend/scripts/frontend-capabilities.test.mjs— only the matching expected-state entries and exact admin role overrides for those five IDsbackend/e2e/issue-218-shared-primitives.spec.js— only one mobile “Schedule actions” disclosure-opening step before its existing Delete actionbackend/e2e/card-template-updates.spec.js,backend/e2e/canonical-capability-behavior.spec.js, orbackend/e2e/canonical-route-parity.spec.jsonly if the post-Converge Wave A surfaces on bounded shared UI primitives #218 inventory proves a minimal pointer/fixture adjustment is required; no journey rewrite or ownership transferAdd only these durable state identities if still absent after #218:
templates.batch-failurerecurring.editor-dirtyrecurring.validationrecurring.savingrecurring.conflictDo not edit backend runtime/routes/tests beyond the two exact test/evidence exceptions above, API schemas, seed contracts, #159 schema/collector/reporter code, shell/runtime/Home/account/team files, or unrelated styles. Any newly required production path or backend contract requires another PM amendment before editing.
Acceptance criteria
Gap-only implementation
Recurring editor lifecycle
Recurring list and mobile disclosure
Template list/detail and batch recovery
Accessibility, responsive, and honest state
Durable real-server behavior and parity
backend/dist, and packaged SAM frontend assets are identical for every changed asset; the normal source/SAM parity run accounts for every evidence record and proves the same route/state behavior.Test scenarios
Dirty recurring draft dismissal
Given a clean edit dialog for a synthetic recurring schedule
When the operator changes description, cadence, assignee, or Active and attempts Close, Cancel, backdrop dismissal, or Escape
Then a discard confirmation appears without losing values
When Keep editing is selected
Then the same values and useful focus remain
When every field is restored to baseline or Discard is selected
Then the dialog closes through the clean/explicit path and focus returns to the connected opener
Validation, saving, conflict, and retry
Given a dirty recurring draft
When required description or cron is invalid
Then exact fields are announced/focused and no request occurs
When a valid draft is submitted twice while the first request is pending
Then one mutation occurs and saving is announced
When the server returns 409 or 503
Then values and dirty state remain, false success never appears, and the corresponding reload/discard or retry path is explicit
Mobile schedule actions and protected delete
Given active, paused, removable, and referenced synthetic schedules at 390×844
When each row disclosure is operated by keyboard/touch
Then only that row exposes Edit, Pause/Resume, and Delete in reading order
When referenced Delete returns authoritative 409
Then the same row remains expanded, generated work is preserved, and Pause guidance is announced and focused
Template batch failure and partial conflict
Given one read-only Template with multiple existing synthetic Cards
When preview fails, succeeds, selected Cards are applied, and one Card conflicts
Then the selected Template and explicit selections/results remain understandable, request failure is assertive/retryable, applied and conflicted Cards are distinct, and the conflict requires a fresh preview without silent retry
Route, responsive, and source/SAM identity
Given direct Templates and Recurring routes on source and clean packaged SAM servers
When the operator searches/selects a Template, uses mobile Back/Forward, opens recurring row actions, edits/discards/saves, and reloads
Then URL/entity/focus and authoritative state agree at 1440×900 and 390×844, and every changed frontend asset and durable evidence record matches across source and SAM
Synthetic screenshot inventory
Capture exactly these 12 untracked native-size PNGs under
.tmp/screenshots/issue-219/; delete stale extras before review:01-source-templates-batch-conflict-desktop-1440x900.png02-sam-templates-batch-conflict-desktop-1440x900.png03-source-templates-detail-mobile-390x844.png04-sam-templates-detail-mobile-390x844.png05-source-recurring-actions-mobile-390x844.png06-sam-recurring-actions-mobile-390x844.png07-source-recurring-dirty-editor-mobile-390x844.png08-sam-recurring-dirty-editor-mobile-390x844.png09-source-recurring-conflict-desktop-1440x900.png10-sam-recurring-conflict-desktop-1440x900.png11-source-recurring-delete-409-desktop-1440x900.png12-sam-recurring-delete-409-desktop-1440x900.pngSource/SAM pairs use identical synthetic fixtures and show the same route, selected entity, expanded/dirty/conflict state, accessible-name summary, and console/page-error result. Designer and Tester inspect every image at native resolution for hierarchy, state/copy ownership, theme/contrast, touch target sizing, overflow, clipping, overlap, first-decision visibility, and public safety. Do not commit, publish, or attach these images to the public issue.
Exact verification
Engineer may run focused tests while iterating.
make test-sam-workspace-isolationis explicitly excluded for this containing baseline under the PM amendment; do not edit its verifier in #219. Independent Tester runs the complete workflow on one frozen diff/status/content fingerprint and records each command, exit code, observed counts, changed behavior titles, capability-state accounting, and evidence paths:The dedicated #219 spec must run inside the normal full Playwright workflow and use its normal capability collector. Do not run raw import/export/migration/restore/data-movement tools, provider actions, AWS commands beyond local SAM validation/build, workflow dispatch, manual deploy, or production/private data checks.
Lifecycle gates
78e91220c89588df809b2e84af02e796d1910a25eea01650c89588df809b2e84af02e796d1910a25eea0165and project-local isolated writer order recordedCloses #219No HUMAN gate is required for this local, synthetic, provider-free slice.
No-backcompat boundary
Make the final behavior atomic. Remove superseded #219-owned markup/selectors/tests in the same change. Do not add aliases, legacy fallbacks, hidden old controls beside new disclosure controls, dual event paths, old/new state readers, temporary feature flags, or version branches. If the accepted #218 primitive cannot express the required behavior, stop for PM amendment instead of creating a parallel primitive.
Explicit exclusions