From aef52eb91e2e01459d29e2b9c6d19614b076b246 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:06:47 -0700 Subject: [PATCH 1/8] test(ui): define assignment history interaction contract --- ...orkspace-assignment-history-state.test.mjs | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/hr-workspace-assignment-history-state.test.mjs diff --git a/tests/hr-workspace-assignment-history-state.test.mjs b/tests/hr-workspace-assignment-history-state.test.mjs new file mode 100644 index 000000000..ae19bf094 --- /dev/null +++ b/tests/hr-workspace-assignment-history-state.test.mjs @@ -0,0 +1,113 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; +import { + assignmentHistoryStateMarkup, + assignmentHistoryViewModel, +} from '../apps/hr-workspace/assignment-history-state.js'; + +const story = readFileSync( + new URL('../apps/hr-workspace/assignment-history-state.stories.js', import.meta.url), + 'utf8', +); +const css = readFileSync( + new URL('../apps/hr-workspace/assignment-history-state.css', import.meta.url), + 'utf8', +); + +const expectedStates = { + idle: ['false', 'status', false, 'default', 'Review assignment history'], + loading: ['true', 'status', true, 'loading', 'Loading assignment history'], + ready: ['false', 'status', true, 'read-only', 'Assignment history ready'], + empty: ['false', 'status', false, 'read-only', 'No assignment history is visible here'], + denied: ['false', 'alert', false, 'permission-denied', 'Assignment history access denied'], + stale: ['false', 'alert', false, 'validation-error', 'Assignment history evidence is stale'], + scopeBlocked: ['false', 'alert', false, 'validation-error', 'Assignment history fields are not authorized'], + error: ['false', 'alert', false, 'error', 'Assignment history unavailable'], +}; + +const allowedViewModelKeys = [ + 'actionDisabled', + 'actionLabel', + 'ariaBusy', + 'ariaLive', + 'interactionState', + 'label', + 'message', + 'nextAction', + 'role', +]; + +test('assignment-history states are bounded, actionable, and privacy-minimized', () => { + for (const [state, [ariaBusy, role, actionDisabled, interactionState, label]] of Object.entries(expectedStates)) { + const model = assignmentHistoryViewModel(state); + assert.equal(model.ariaBusy, ariaBusy); + assert.equal(model.role, role); + assert.equal(model.actionDisabled, actionDisabled); + assert.equal(model.interactionState, interactionState); + assert.equal(model.label, label); + assert.equal(model.ariaLive, role === 'alert' ? 'assertive' : 'polite'); + assert.match(model.nextAction, /\.$/); + assert.deepEqual(Object.keys(model).sort(), allowedViewModelKeys); + + for (const forbiddenKey of [ + 'personRecordId', 'employmentRecordId', 'assignmentRecordId', 'jobRecordId', + 'positionRecordId', 'organizationRecordId', 'workerName', 'email', 'phone', + 'compensationValue', 'ratingValue', 'assessmentScore', 'candidateRecordId', + 'credential', 'token', 'prompt', 'modelOutput', + ]) { + assert.equal(Object.hasOwn(model, forbiddenKey), false); + } + + const markup = assignmentHistoryStateMarkup(state); + assert.match(markup, /data-figma-node-id="1:64"/); + assert.match(markup, new RegExp(`data-interaction-state="${interactionState}"`)); + assert.match(markup, new RegExp(`aria-busy="${ariaBusy}"`)); + assert.match(markup, /Next action/); + if (actionDisabled) assert.match(markup, /]* disabled/); + else assert.doesNotMatch(markup, /]* disabled/); + } +}); + +test('ready evidence explains bitemporal meaning without granting mutation authority', () => { + const ready = assignmentHistoryViewModel('ready'); + assert.match(ready.message, /read-only bitemporal Assignment history/i); + assert.match(ready.message, /effective time/i); + assert.match(ready.message, /system-recorded time/i); + assert.match(ready.message, /does not authorize/i); + assert.match(ready.message, /exact known-at snapshot/i); + assert.match(ready.nextAction, /separately authorized change/i); +}); + +test('empty, stale, and scope-blocked states prevent unsafe inference', () => { + assert.match(assignmentHistoryViewModel('empty').message, /not evidence of no Employment/i); + assert.match(assignmentHistoryViewModel('stale').nextAction, /Reload/i); + assert.match(assignmentHistoryViewModel('scopeBlocked').nextAction, /Narrow the requested fields/i); + assert.match(assignmentHistoryViewModel('error').nextAction, /Do not infer/i); +}); + +test('unsupported and prototype-inherited runtime state names fail closed before rendering', () => { + for (const value of ['current', 'constructor', 'toString', '__proto__']) { + assert.throws(() => assignmentHistoryViewModel(value), /unsupported assignment-history state/); + assert.throws(() => assignmentHistoryStateMarkup(value), /unsupported assignment-history state/); + } + assert.throws(() => assignmentHistoryViewModel(new String('ready')), /exact built-in string/); + assert.throws(() => assignmentHistoryStateMarkup(Symbol('ready')), /exact built-in string/); +}); + +test('Storybook and CSS cover the governed assignment-history accessibility states', () => { + for (const storyName of [ + 'Idle', 'Loading', 'ReadyReadOnly', 'Empty', 'PermissionDenied', + 'StaleEvidence', 'ScopeBlocked', 'Error', + ]) { + assert.match(story, new RegExp(`export const ${storyName}`)); + } + assert.match(story, /assignmentHistoryStateMarkup/); + assert.match(css, /var\(--orgmetra-focus-ring\)/); + assert.match(css, /:focus-visible/); + assert.match(css, /\[aria-busy="true"\]/); + assert.match(css, /read-only/); + assert.match(css, /permission-denied/); + assert.match(css, /validation-error/); + assert.match(css, /min-height:\s*44px/); +}); From 838bea43b6264d2cc1148c5acacea3a64319c76a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:07:02 -0700 Subject: [PATCH 2/8] ci(ui): add assignment history exact-coverage gate --- .../hr-workspace-assignment-history-state.yml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/hr-workspace-assignment-history-state.yml diff --git a/.github/workflows/hr-workspace-assignment-history-state.yml b/.github/workflows/hr-workspace-assignment-history-state.yml new file mode 100644 index 000000000..220917c66 --- /dev/null +++ b/.github/workflows/hr-workspace-assignment-history-state.yml @@ -0,0 +1,54 @@ +name: HR Workspace Assignment History State Quality + +on: + pull_request: + branches: + - feat/hr-workspace-protected-read-state + paths: + - "apps/hr-workspace/assignment-history-state.js" + - "apps/hr-workspace/assignment-history-state.css" + - "apps/hr-workspace/assignment-history-state.stories.js" + - "tests/hr-workspace-assignment-history-state.test.mjs" + - "docs/traceability/hr-workspace-assignment-history-state.md" + - "docs/doctoring/hr-workspace-assignment-history-accessibility-references.md" + - ".github/workflows/hr-workspace-assignment-history-state.yml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: hr-workspace-assignment-history-state-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + assignment-history-state: + name: Assignment history state contract + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout exact candidate + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Prove exact candidate checkout + env: + ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" + - name: Set up Node.js LTS + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "24" + check-latest: false + - name: Run assignment-history accessibility contract with exact coverage + run: >- + node --test --experimental-test-coverage + --test-coverage-lines=100 + --test-coverage-branches=100 + --test-coverage-functions=100 + tests/hr-workspace-assignment-history-state.test.mjs + - name: Require clean checkout + run: | + git diff --exit-code + test -z "$(git status --porcelain)" From 4a3c049050bf54bdf43221e37dc230a16c00e12d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:07:58 -0700 Subject: [PATCH 3/8] feat(ui): implement assignment history read states --- apps/hr-workspace/assignment-history-state.js | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 apps/hr-workspace/assignment-history-state.js diff --git a/apps/hr-workspace/assignment-history-state.js b/apps/hr-workspace/assignment-history-state.js new file mode 100644 index 000000000..46eb1369e --- /dev/null +++ b/apps/hr-workspace/assignment-history-state.js @@ -0,0 +1,80 @@ +const STATE_MODELS = Object.freeze({ + idle: Object.freeze({ + ariaBusy: 'false', ariaLive: 'polite', role: 'status', actionDisabled: false, + interactionState: 'default', actionLabel: 'Load assignment history', + label: 'Review assignment history', + message: 'Load fresh purpose-authorized Assignment history for the requested business-time and system-knowledge coordinate.', + nextAction: 'Load the current authorized Assignment history before relying on this Employee Profile evidence.', + }), + loading: Object.freeze({ + ariaBusy: 'true', ariaLive: 'polite', role: 'status', actionDisabled: true, + interactionState: 'loading', actionLabel: 'Loading assignment history', + label: 'Loading assignment history', + message: 'Orgmetra is resolving the authorized fields and visible Assignment versions at the requested known-at coordinate.', + nextAction: 'Wait for the governed Assignment-history read to finish.', + }), + ready: Object.freeze({ + ariaBusy: 'false', ariaLive: 'polite', role: 'status', actionDisabled: true, + interactionState: 'read-only', actionLabel: 'Assignment history loaded', + label: 'Assignment history ready', + message: 'This is read-only bitemporal Assignment history. Effective time shows when a fact applied; system-recorded time shows when Orgmetra knew it. This evidence does not authorize Assignment mutation and does not infer current worker status beyond the exact known-at snapshot.', + nextAction: 'Use only the authorized visible fields; start a separately authorized change if Assignment truth must be updated.', + }), + empty: Object.freeze({ + ariaBusy: 'false', ariaLive: 'polite', role: 'status', actionDisabled: false, + interactionState: 'read-only', actionLabel: 'Reload assignment history', + label: 'No assignment history is visible here', + message: 'No Assignment version is visible at this authorized business-time and known-at coordinate. This is not evidence of no Employment or no Assignment evidence outside this coordinate.', + nextAction: 'Check the authorized time coordinate and reload if another business-time or known-at view is required.', + }), + denied: Object.freeze({ + ariaBusy: 'false', ariaLive: 'assertive', role: 'alert', actionDisabled: false, + interactionState: 'permission-denied', actionLabel: 'Review access', + label: 'Assignment history access denied', + message: 'The current purpose or actor authority does not permit this Assignment-history read.', + nextAction: 'Check the HR purpose and access authority before requesting Assignment history again.', + }), + stale: Object.freeze({ + ariaBusy: 'false', ariaLive: 'assertive', role: 'alert', actionDisabled: false, + interactionState: 'validation-error', actionLabel: 'Reload assignment history', + label: 'Assignment history evidence is stale', + message: 'The requested known-at coordinate or authoritative Assignment evidence changed before this view could be relied on.', + nextAction: 'Reload the purpose-authorized Assignment history at an explicit fresh known-at coordinate.', + }), + scopeBlocked: Object.freeze({ + ariaBusy: 'false', ariaLive: 'assertive', role: 'alert', actionDisabled: false, + interactionState: 'validation-error', actionLabel: 'Narrow requested fields', + label: 'Assignment history fields are not authorized', + message: 'One or more requested Assignment-history fields fall outside the current purpose-bound authorization.', + nextAction: 'Narrow the requested fields to the authorized set or obtain the required HR access before retrying.', + }), + error: Object.freeze({ + ariaBusy: 'false', ariaLive: 'assertive', role: 'alert', actionDisabled: false, + interactionState: 'error', actionLabel: 'Retry governed read', + label: 'Assignment history unavailable', + message: 'The governed Assignment-history read did not return usable authoritative evidence.', + nextAction: 'Do not infer Assignment or Employment status from cached or partial data; verify the service and authorization before retrying.', + }), +}); + +function requireExactState(value) { + if (typeof value !== 'string') { + throw new TypeError('assignment-history state must be an exact built-in string'); + } + if (!Object.hasOwn(STATE_MODELS, value)) { + throw new TypeError(`unsupported assignment-history state: ${value}`); + } + return STATE_MODELS[value]; +} + +/** Return immutable accessibility semantics for one purpose-bound Assignment-history interaction state. */ +export function assignmentHistoryViewModel(state) { + return requireExactState(state); +} + +/** Render static Storybook evidence without accepting caller-controlled HR values or identifiers. */ +export function assignmentHistoryStateMarkup(state) { + const model = requireExactState(state); + const disabled = model.actionDisabled ? ' disabled' : ''; + return `
\n

${model.label}${model.message}

\n

Next action${model.nextAction}

\n \n
`; +} From d530f720f3c4c512c8f113cac0aa6b95d690f64a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:08:08 -0700 Subject: [PATCH 4/8] feat(ui): style assignment history read states --- .../hr-workspace/assignment-history-state.css | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 apps/hr-workspace/assignment-history-state.css diff --git a/apps/hr-workspace/assignment-history-state.css b/apps/hr-workspace/assignment-history-state.css new file mode 100644 index 000000000..d352c9b60 --- /dev/null +++ b/apps/hr-workspace/assignment-history-state.css @@ -0,0 +1,58 @@ +.assignment-history-state { + display: grid; + gap: var(--orgmetra-space-md); + max-width: 42rem; + padding: var(--orgmetra-space-lg); + border: 1px solid var(--orgmetra-border-subtle); + border-radius: var(--orgmetra-radius-md); + background: var(--orgmetra-surface-card); + color: var(--orgmetra-text-primary); +} + +.assignment-history-status, +.assignment-history-next-action { + display: grid; + gap: var(--orgmetra-space-xs); + margin: 0; +} + +.assignment-history-status span, +.assignment-history-next-action span { + color: var(--orgmetra-text-muted); +} + +.assignment-history-state[data-interaction-state="read-only"] { + border-color: var(--orgmetra-border-subtle); +} + +.assignment-history-state[data-interaction-state="permission-denied"], +.assignment-history-state[data-interaction-state="validation-error"], +.assignment-history-state[data-interaction-state="error"] { + border-color: var(--orgmetra-danger); +} + +.assignment-history-state[aria-busy="true"] { + cursor: progress; +} + +.assignment-history-action { + justify-self: start; + min-height: 44px; + padding: var(--orgmetra-space-sm) var(--orgmetra-space-md); + border: 0; + border-radius: var(--orgmetra-radius-sm); + background: var(--orgmetra-action-review); + color: #fff; + font: inherit; + cursor: pointer; +} + +.assignment-history-action:disabled { + cursor: not-allowed; + opacity: 0.62; +} + +.assignment-history-action:focus-visible { + outline: 3px solid var(--orgmetra-focus-ring); + outline-offset: 3px; +} From ea7782553d403ae09bfe2ea89b931d52ef26ff1e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:08:20 -0700 Subject: [PATCH 5/8] feat(ui): add assignment history Storybook states --- .../assignment-history-state.stories.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 apps/hr-workspace/assignment-history-state.stories.js diff --git a/apps/hr-workspace/assignment-history-state.stories.js b/apps/hr-workspace/assignment-history-state.stories.js new file mode 100644 index 000000000..6995bf61c --- /dev/null +++ b/apps/hr-workspace/assignment-history-state.stories.js @@ -0,0 +1,25 @@ +import { assignmentHistoryStateMarkup } from './assignment-history-state.js'; +import './assignment-history-state.css'; + +export default { + title: 'HR Workspace/Assignment History States', + parameters: { + design: { + type: 'figma', + url: 'Orgmetra Baseline — Storybook Inventory node 1:64', + }, + }, +}; + +function story(state) { + return () => assignmentHistoryStateMarkup(state); +} + +export const Idle = story('idle'); +export const Loading = story('loading'); +export const ReadyReadOnly = story('ready'); +export const Empty = story('empty'); +export const PermissionDenied = story('denied'); +export const StaleEvidence = story('stale'); +export const ScopeBlocked = story('scopeBlocked'); +export const Error = story('error'); From a63e7023d9dec28f4568e05dcdd57ef4e8a27f26 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:08:32 -0700 Subject: [PATCH 6/8] docs(ui): record assignment history accessibility references --- ...gnment-history-accessibility-references.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/doctoring/hr-workspace-assignment-history-accessibility-references.md diff --git a/docs/doctoring/hr-workspace-assignment-history-accessibility-references.md b/docs/doctoring/hr-workspace-assignment-history-accessibility-references.md new file mode 100644 index 000000000..9a6142aa6 --- /dev/null +++ b/docs/doctoring/hr-workspace-assignment-history-accessibility-references.md @@ -0,0 +1,22 @@ +# HR Workspace Assignment History accessibility references + +Reviewed: 2026-08-28 (Asia/Seoul) + +This note records design inputs for the active Assignment-history interaction slice. It is evidence for engineering decisions, not a claim of accessibility certification or legal compliance. + +## Primary standards + +World Wide Web Consortium. (2024, December 12). *Web Content Accessibility Guidelines (WCAG) 2.2*. https://www.w3.org/TR/WCAG22/ + +World Wide Web Consortium. (2023, June 6). *Accessible Rich Internet Applications (WAI-ARIA) 1.2*. https://www.w3.org/TR/wai-aria-1.2/ + +World Wide Web Consortium. (2025, October 21). *Web Content Accessibility Guidelines (WCAG) 2.2 approved as ISO/IEC international standard*. https://www.w3.org/press-releases/2025/wcag22-iso-pas/ + +## Applied consequences + +- Loading is perceivable through `aria-busy=true`, and transient status updates use a polite live region. +- Permission, stale-evidence, field-scope, and transport failures use assertive alert semantics and provide a concrete next action. +- Keyboard focus remains visible through the existing Orgmetra focus token; actionable controls preserve a 44px minimum target height. +- Loaded Assignment history remains explicitly read-only. UI evidence does not grant Assignment mutation authority or consequential employment-decision authority. +- Empty and stale states prohibit inference beyond the exact authorized business-time and system-knowledge coordinate. +- Figma `Orgmetra Baseline` Storybook Inventory node `1:64` was freshly re-read on 2026-08-28 and continues to require default, hover, focus, disabled, loading, validation-error, read-only, and high-risk-confirmation interaction states. This slice reuses that design system rather than introducing parallel geometry or tokens. From 5e8bd65a60c8b53b039e848907b99f4456e27085 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 23:08:49 -0700 Subject: [PATCH 7/8] docs(ui): trace assignment history interaction boundary --- .../hr-workspace-assignment-history-state.md | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 docs/traceability/hr-workspace-assignment-history-state.md diff --git a/docs/traceability/hr-workspace-assignment-history-state.md b/docs/traceability/hr-workspace-assignment-history-state.md new file mode 100644 index 000000000..515661211 --- /dev/null +++ b/docs/traceability/hr-workspace-assignment-history-state.md @@ -0,0 +1,38 @@ +# HR Workspace Assignment History interaction traceability + +Status: **active PR only; not protected-main truth**. + +## Buyer need + +The PRD identifies Employee Profile with bitemporal Assignment history as a P1 HRIS surface. A customer needs to understand what Assignment evidence was effective and what Orgmetra knew at a selected system-knowledge coordinate without converting that read into mutation authority or leaking fields outside the authorized HR purpose. + +## Ownership boundary + +- PR #142 owns the separate purpose-bound People API Assignment-history read contract. Its active-PR backend evidence does not transfer into this UI lane. +- PR #130 owns the shared protected-read accessibility semantics and Figma/Storybook interaction system. +- This child owns **presentation/interaction only** for Assignment history. It introduces no Assignment writer, no cross-service SQL, and no dedicated-writer dependency mutation. + +## Governed interaction evidence + +`apps/hr-workspace/assignment-history-state.js` exposes only constant, value-minimized state semantics for `idle`, `loading`, `ready`, `empty`, `denied`, `stale`, `scopeBlocked`, and `error`. + +The `ready` state explains the bitemporal distinction: effective time is when the Assignment fact applied; system-recorded time is when Orgmetra knew it. The state is read-only and cannot authorize Assignment mutation. `empty`, `stale`, and failure states prohibit inference outside the exact authorized business-time and known-at coordinate. + +The view model intentionally carries no Person, Employment, Assignment, Job, Position, or Organization identifiers; worker names/contact data; compensation, rating, assessment, or candidate values; credentials/tokens; prompts; or model output. Actual authorized HR values remain backend response data and must be handled through purpose-bound field authorization rather than embedded in generic UI-state evidence. + +## Design and accessibility evidence + +Figma `Orgmetra Baseline` Storybook Inventory node `1:64` was freshly re-read on 2026-08-28. The executable Storybook stories correlate to that node and reuse existing Orgmetra CSS tokens, visible `:focus-visible` treatment, loading semantics, read-only presentation, failure alerts, and 44px action target sizing. Current W3C WCAG 2.2 and WAI-ARIA 1.2 references are recorded under `docs/doctoring/hr-workspace-assignment-history-accessibility-references.md`. + +## Executable acceptance + +`tests/hr-workspace-assignment-history-state.test.mjs` requires: + +- the full bounded state set and concrete next actions; +- read-only bitemporal explanation without mutation authority; +- no unsafe inference from empty/stale/scope-blocked/error states; +- exact built-in string state names and rejection of prototype-inherited names such as `constructor`, `toString`, and `__proto__`; +- Figma node correlation, Storybook inventory, existing focus/design tokens, loading/read-only/failure CSS states, and 44px action target; and +- exact 100% owned line, branch, and function coverage in the dedicated workflow. + +After #53 and #130 integrate dependency-first, this child must be retargeted to fresh `develop`, reconciled with then-current Employee Profile and #142 backend truth, and rerun through applicable browser/accessibility/Foundation/Recovery/SAST/Security and central required workflows. No parent or predecessor check/review transfers. From b7fdd493809545a7fd562fb6464b09c853739149 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 03:13:33 +0900 Subject: [PATCH 8/8] ci: rerun assignment history checks on develop --- .../workflows/hr-workspace-assignment-history-state.yml | 1 + tests/hr-workspace-assignment-history-state.test.mjs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/hr-workspace-assignment-history-state.yml b/.github/workflows/hr-workspace-assignment-history-state.yml index 220917c66..af376c572 100644 --- a/.github/workflows/hr-workspace-assignment-history-state.yml +++ b/.github/workflows/hr-workspace-assignment-history-state.yml @@ -3,6 +3,7 @@ name: HR Workspace Assignment History State Quality on: pull_request: branches: + - develop - feat/hr-workspace-protected-read-state paths: - "apps/hr-workspace/assignment-history-state.js" diff --git a/tests/hr-workspace-assignment-history-state.test.mjs b/tests/hr-workspace-assignment-history-state.test.mjs index ae19bf094..8eac87365 100644 --- a/tests/hr-workspace-assignment-history-state.test.mjs +++ b/tests/hr-workspace-assignment-history-state.test.mjs @@ -14,6 +14,10 @@ const css = readFileSync( new URL('../apps/hr-workspace/assignment-history-state.css', import.meta.url), 'utf8', ); +const workflow = readFileSync( + new URL('../.github/workflows/hr-workspace-assignment-history-state.yml', import.meta.url), + 'utf8', +); const expectedStates = { idle: ['false', 'status', false, 'default', 'Review assignment history'], @@ -111,3 +115,7 @@ test('Storybook and CSS cover the governed assignment-history accessibility stat assert.match(css, /validation-error/); assert.match(css, /min-height:\s*44px/); }); + +test('the dedicated contract reruns after retargeting to protected develop', () => { + assert.match(workflow, /branches:\n\s+- develop\n\s+- feat\/hr-workspace-protected-read-state/); +});