diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 1da833955..64fa26e0d 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -50,6 +50,10 @@ jobs: run: python -m compileall -q tests - name: Validate foundation pack run: npm run validate + - name: Install Node dependencies + run: npm ci + - name: Build Storybook + run: npm run build-storybook - name: Prove Foundation CI dependency hygiene run: bash tests/test_foundation_ci_dependency_hygiene.sh - name: Prove HRIS kernel diff --git a/.github/workflows/hr-workspace-browser-e2e.yml b/.github/workflows/hr-workspace-browser-e2e.yml new file mode 100644 index 000000000..e59a70c1c --- /dev/null +++ b/.github/workflows/hr-workspace-browser-e2e.yml @@ -0,0 +1,57 @@ +name: HR Workspace Browser E2E + +on: + pull_request: + branches: + - develop + paths: + - "apps/hr-workspace/**" + - "packages/design-tokens/**" + - "tests/e2e/**" + - "playwright.config.mjs" + - "package.json" + - "package-lock.json" + - ".github/workflows/hr-workspace-browser-e2e.yml" + - "tests/validate_repository.py" + - "scripts/foundation-contract-core.mjs" + - "manifest.json" + - "docs/STORYBOOK.md" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: hr-workspace-browser-e2e-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + browser: + name: HR workspace Chromium E2E + runs-on: ubuntu-latest + timeout-minutes: 20 + 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: Install Node dependencies + run: npm ci + - name: Install Chromium and Linux dependencies + run: npx playwright install --with-deps chromium + - name: Run HR workspace browser E2E + run: npm run test:e2e + - name: Require clean checkout + run: | + git diff --exit-code + test -z "$(git status --porcelain)" diff --git a/.gitignore b/.gitignore index 1f0b61ba5..e5d4913eb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ node_modules/ dist/ coverage/ .turbo/ +storybook-static/ +playwright-report/ +test-results/ # Rust /target/ @@ -35,3 +38,4 @@ secrets/ artifacts/ reports/ *.log +/.codegraph/ diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 000000000..87fa64439 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,8 @@ +/** @type { import('@storybook/web-components-vite').StorybookConfig } */ +const config = { + stories: ['../apps/hr-workspace/**/*.stories.@(js|mjs)'], + framework: '@storybook/web-components-vite', + docs: { autodocs: 'tag' } +}; + +export default config; diff --git a/.storybook/preview.js b/.storybook/preview.js new file mode 100644 index 000000000..058f02b9b --- /dev/null +++ b/.storybook/preview.js @@ -0,0 +1,13 @@ +import '../packages/design-tokens/tokens.css'; +import '../apps/hr-workspace/styles.css'; + +/** @type { import('storybook').Preview } */ +const preview = { + parameters: { + layout: 'centered', + controls: { expanded: true } + }, + decorators: [(story) => `
${story()}
`] +}; + +export default preview; diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1bdc13b5a..2eb436f71 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -76,7 +76,7 @@ The initial deployment may share one physical PostgreSQL cluster. Logical isolat |---|---|---| | `people_core` | `people_core`: person, name, employment, assignment, compensation, and candidate-worker linkage records | `people_core_role` | | `organization_core` | `organization_core`: organization units and position records | `organization_core_role` | -| `job_architecture` | `job_architecture`: job profiles, publication evidence, and persisted `job_analysis_snapshot` / task / KSAO rows | `job_architecture_role` | +| `job_architecture` | `job_architecture`: job profiles and publication evidence | `job_architecture_role` | | `talent_acquisition` | `talent_acquisition`: candidate profiles, selection decisions, and decision evidence | `talent_acquisition_role` | | `performance_management` | `performance_management`: criterion blueprints and observations | `performance_management_role` | | `workforce_validation` | `workforce_validation`: validity-study registry and external result references | `workforce_validation_role` | diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f4752d7..53b1df504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,22 +6,27 @@ All notable changes to Orgmetra will be documented in this file. ### Added +- Dependency-free HR Home and Employee Profile fixture at `apps/hr-workspace/`, using the Figma role frames and shared tokens with explicit API-boundary, permission-denied, evidence-drawer, high-impact confirmation, exact-allocation, focus, and English/Korean states. The fixture is not connected or deployed evidence. +- Local Storybook `10.5.10` runtime using `@storybook/web-components-vite` and native HTML/CSS stories for the HR action states, field errors, permission denial, evidence drawer, high-impact confirmation, and exact assignment values. It is local component/state evidence, not connected People API or browser E2E evidence. +- Chromium Playwright browser E2E for the HR workspace, covering keyboard-accessible human review, locale changes, purpose-bound denial, host-injected People and Job Analysis reads, authorization headers, and no-fallback error behavior. The test is local/CI evidence and does not claim protected deployment. +- Product and technical gap baseline with protected-branch truth, full current open-PR inventory, buyer-priority acceptance evidence, Figma source ID, standards/research ledger, and central integration-loop contract. The baseline distinguishes shipped runtime from active PR, accepted architecture, planned, research-only, superseded, and out-of-scope work. +- Project-local `uv` source resolution and a checked lockfile for `services/people-api`, so local tests discover the owned Keyverse adapter without an undocumented `PYTHONPATH` workaround. +- Project-local `uv` source resolution, Python compatibility metadata, test extras, and a checked lockfile for `services/job-analysis-api`, so its full test command resolves owned packages without an undocumented `PYTHONPATH` workaround. - Accepted ADRs 0001–0003 now include buyer-facing Context, Decision, and Consequences grounded in verified ISO 30400:2022, ISO 30414:2025, Uniform Guidelines (29 C.F.R. Part 1607), SIOP (2018), OpenAPI Specification v3.2.0, OpenID Connect Core 1.0 errata set 2, CloudEvents v1.0.2, Jensen and Snodgrass (1999), Snodgrass (1999), and Allen (1983) records already listed in `docs/doctoring/REFERENCES.md`. ADRs 0004 and 0005 gained APA 7th References pointers to that same bibliography without changing their Decision bodies. -- Active-PR governed Job Analysis persistence/API on the canonical `JobAnalysisSnapshot` model: migration `0013_job_analysis_snapshot.sql` stores immutable tenant-scoped snapshot, Task, KSAO, Task–KSAO, FJA and write-command evidence; `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots` and matching GET enforce purpose-bound Keyverse scope, authenticated-principal actor authority, bounded/strict JSON handling, transactional Idempotency-Key serialization, parent-scope fail-closed integrity, forced RLS, and atomic audit/outbox evidence. ADR 0014 records the persistence decision while ADR 0007 remains the domain/evidence authority; validated evidence still requires accountable human review and non-LLM provenance, and the service does not make a high-impact employment decision. -- Active-PR `orgmetra_selection_review` packet for PII-minimized, evidence-bound human selection review: canonical operational tenant identity, UUID-backed opaque candidate/Job/sealed-evidence/reviewer references, explicit purpose/reason/evidence version, deterministic canonical JSON and SHA-256 correlation, mandatory human decision state, redacted packet repr, and provenance-paired model evidence that remains `untrusted_draft`, with exact 100% owned statement and branch coverage required by its quality gate. -- Active performance-criterion scope hardening: `criterion_observation_scope_guard` rejects criterion outcomes for a Job the worker did not effectively hold at the observation date, observations before the relevant assignment, and observations outside the referenced performance cycle while preserving valid multiple-assignment cases and existing bitemporal correction semantics. The guard evaluates current-recorded facts, derives the date coordinate from `observed_at` in UTC so session `TimeZone` cannot alter the result, uses a trusted function search path, and adds no PII or automated employment decision authority. The Foundation PostgreSQL contract also rejects a closed `recorded_to` on each time-coordinate lookup and proves UTC midnight plus non-UTC session `TimeZone` boundaries. +- Protected `orgmetra_selection_review` packet for PII-minimized, evidence-bound human selection review: canonical operational tenant identity, UUID-backed opaque candidate/Job/sealed-evidence/reviewer references, explicit purpose/reason/evidence version, deterministic canonical JSON and SHA-256 correlation, mandatory human decision state, redacted packet repr, and provenance-paired model evidence that remains `untrusted_draft`, with exact 100% owned statement and branch coverage required by its quality gate. +- Protected performance-criterion scope hardening: `criterion_observation_scope_guard` rejects criterion outcomes for a Job the worker did not effectively hold at the observation date, observations before the relevant assignment, and observations outside the referenced performance cycle while preserving valid multiple-assignment cases and existing bitemporal correction semantics. The guard evaluates current-recorded facts, derives the date coordinate from `observed_at` in UTC so session `TimeZone` cannot alter the result, uses a trusted function search path, and adds no PII or automated employment decision authority. The Foundation PostgreSQL contract also rejects a closed `recorded_to` on each time-coordinate lookup and proves UTC midnight plus non-UTC session `TimeZone` boundaries. - Bitemporal tenant-scoped organization hierarchy validation that rejects visible indirect parent cycles and reuses single-valued recorded-time reconstruction before graph traversal. -- Stacked governed job-analysis evidence contract via `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `TaskKSAOLink`, `FunctionalJobAnalysisProfile`, and `EvidenceSource`: tenant/Job-scoped observable tasks, explicit Task-to-KSAO linkage, importance/difficulty/proficiency ratings, source/version/retrieval/SHA-256 provenance, deterministic canonical snapshot bytes, current O*NET evidence support, and historical DOT Data/People/Things compatibility. Validated snapshots require accountable human review and complete non-LLM evidence; LLM-origin material remains `analysis_draft`, and the snapshot is evidence input rather than a hiring, promotion, termination, compensation, or other high-impact employment decision. -- Stacked governed audit/outbox slice via `AuditOutboxEvent`, `audit_event_record`, `outbox_delivery_record`, and `outbox_delivery_escalation_record`: CloudEvents 1.0-compatible PII-minimized metadata, exact canonical JSON bytes, database-verified SHA-256 digests, mandatory human confirmation for high-impact events, immutable audit evidence, tenant RLS, atomic audit/outbox insertion, guarded pending/leased/delivered/dead-lettered delivery state, tenant-safe `claim_outbox_delivery(...)` with deterministic due-work ordering, `FOR UPDATE ... SKIP LOCKED`, opaque worker identity, bounded future leases, immutable envelope return, and atomic takeover of genuinely expired leases only while retry attempts remain; owner-bound `complete_outbox_delivery(...)` and `retry_outbox_delivery(...)`; database-budget-governed `dead_letter_outbox_delivery(...)`; and a separately privileged `operator_dead_letter_expired_outbox_delivery(...)` recovery path for an exhausted final lease whose recorded worker identity is permanently unavailable. `maximum_attempt_count` is persisted on the delivery row, defaults to 5, is constrained to 1 through 100, and cannot be lowered by a dispatcher during finalization. Migration 0007 prevents retry or expired-lease takeover from creating attempt N+1; migration 0008 adds TRUNCATE guards, trusted function search paths, a concurrently built due-work partial index, session-independent immutable envelope validation, and operator recovery backed by separate NOLOGIN/NOBYPASSRLS owner/capability roles so the externally assignable operator role can invoke recovery without receiving direct transport-table read/write rights. Migration 0008 also rejects pre-existing reserved recovery-role names before project DDL, atomically contains the temporary schema-creation privilege used for function ownership handoff, and forces deferred escalation binding while the narrow SECURITY DEFINER owner is still active. Exponential/backoff policy selection, policy-specific producer configuration, and external delivery receipts remain subsequent work. +- Protected governed job-analysis evidence contract via `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `TaskKSAOLink`, `FunctionalJobAnalysisProfile`, and `EvidenceSource`: tenant/Job-scoped observable tasks, explicit Task-to-KSAO linkage, importance/difficulty/proficiency ratings, source/version/retrieval/SHA-256 provenance, deterministic canonical snapshot bytes, current O*NET evidence support, and historical DOT Data/People/Things compatibility. Validated snapshots require accountable human review and complete non-LLM evidence; LLM-origin material remains `analysis_draft`, and the snapshot is evidence input rather than a hiring, promotion, termination, compensation, or other high-impact employment decision. +- Protected governed audit/outbox slice via `AuditOutboxEvent`, `audit_event_record`, `outbox_delivery_record`, and `outbox_delivery_escalation_record`: CloudEvents 1.0-compatible PII-minimized metadata, exact canonical JSON bytes, database-verified SHA-256 digests, mandatory human confirmation for high-impact events, immutable audit evidence, tenant RLS, atomic audit/outbox insertion, guarded pending/leased/delivered/dead-lettered delivery state, tenant-safe `claim_outbox_delivery(...)` with deterministic due-work ordering, `FOR UPDATE ... SKIP LOCKED`, opaque worker identity, bounded future leases, immutable envelope return, and atomic takeover of genuinely expired leases only while retry attempts remain; owner-bound `complete_outbox_delivery(...)` and `retry_outbox_delivery(...)`; database-budget-governed `dead_letter_outbox_delivery(...)`; and a separately privileged `operator_dead_letter_expired_outbox_delivery(...)` recovery path for an exhausted final lease whose recorded worker identity is permanently unavailable. `maximum_attempt_count` is persisted on the delivery row, defaults to 5, is constrained to 1 through 100, and cannot be lowered by a dispatcher during finalization. Migration 0007 prevents retry or expired-lease takeover from creating attempt N+1; migration 0008 adds TRUNCATE guards, trusted function search paths, a concurrently built due-work partial index, session-independent immutable envelope validation, and operator recovery backed by separate NOLOGIN/NOBYPASSRLS owner/capability roles so the externally assignable operator role can invoke recovery without receiving direct transport-table read/write rights. Migration 0008 also rejects pre-existing reserved recovery-role names before project DDL, atomically contains the temporary schema-creation privilege used for function ownership handoff, and forces deferred escalation binding while the narrow SECURITY DEFINER owner is still active. Exponential/backoff policy selection, policy-specific producer configuration, and external delivery receipts remain subsequent work. - `orgmetra_hris_kernel` 0.4.0 with exclusive-versus-concurrent employment, staffable position coverage, exclusive-seat capacity, and `validate_assignment_write` at 100% statement and branch coverage. -- `POST /v1/employment-records`, `POST /v1/position-records`, and `POST /v1/assignment-records` with the same Keyverse mutation context, confirmation, and versioned evidence composition as other high-impact commands. +- Protected governed People mutation and confirmed-hire materialization runtime for `POST /v1/employment-records`, `POST /v1/position-records`, `POST /v1/assignment-records`, and the tenant-bound conversion route, with purpose-bound Keyverse mutation context, explicit confirmation, versioned evidence, atomic audit/outbox persistence, and tenant-scoped idempotency. - `employment_record_version.employment_concurrency_code` constrained to `exclusive` or `concurrent`. - ADR 0005 for exclusive employment and staffable seats. - `orgmetra_hris_kernel` 0.3.0 with identity-scoped bitemporal resolution, assignment-employment coverage, allocation-portfolio checks, and a Memorial Hospital RN correction case at 100% statement and branch coverage. - `employment_record_version` and `position_record_version` so employment and position identity stay stable across retroactive corrections. - `assignment_record.employment_record_id` bound to the same person as the covering employment. - `orgmetra_keyverse_adapter` that binds an opaque Keyverse subject to a person and rejects passwords, passkeys, and tokens. -- Design tokens for the repeating HR actions: approve, review, correct, request evidence, compare, export, and escalate. +- Design tokens for the repeating HR actions: approve, review, correct, request evidence, compare, export, escalate. - ADR 0004 for employment/position versions and assignment-employment binding. - Foundation product baseline for Orgmetra as an evidence-centered HRIS/HCM. - CWL federated integration boundary map. @@ -37,6 +42,8 @@ All notable changes to Orgmetra will be documented in this file. ### Changed +- Aligned the English/Korean locale toggle's accessible name with its visible target-language label (`한국어` / `English`) and added exact browser assertions for both language states, following WCAG 2.2 Success Criterion 2.5.3 (Label in Name); the APA 7 W3C citation remains in `docs/doctoring/REFERENCES.md`. +- Reconciled README, traceability, ADR status/index, and changelog maturity claims with capabilities already integrated on protected `develop`; open-PR capabilities remain explicitly non-shipped. - New predictive-validity membership must use one normalized worker-level case; the three independent validity-study decision/evidence/outcome link relations are historical read surfaces only and can no longer accept new rows. A case insert also rejects a criterion observation whose recorded interval is already closed at `linked_at`. - Canonicalized service identifiers as two-or-more-word `snake_case` across architecture, deployment, ACL, metrics, and client contracts. - Separated fast-mlsirm, TEPP, and Psychometrics Commons into immutable external scientific contracts. @@ -73,4 +80,4 @@ All notable changes to Orgmetra will be documented in this file. ### Notes -- Protected `develop` at `e7ddb7a78a5e1460410005d10f43ebf18c5e12e4` includes normalized validity-study and criterion integrity, bitemporal workforce composition, governed candidate-to-worker conversion, purpose-bound PII authorization, GET-only People reads, governed People mutation/idempotency API, and the accepted ADR 0001–0003 source expansion integrated by #37. Job Analysis persistence/API and the selection-review packet remain active-PR truth until their unchanged exact heads satisfy fresh gates and merge. +- Protected `develop` is the shipped repository truth for integrated capability. Open PRs and draft branches are non-shipped until they integrate and satisfy fresh exact-head gates. diff --git a/README.md b/README.md index 47bb087a3..dd335b0ff 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,10 @@ Job evidence - `docs/TEST_STRATEGY.md` - `docs/OPERABILITY.md` - `docs/TRACEABILITY.md` +- `docs/product-technical-gap-baseline.md` - `docs/adr/README.md` - `docs/doctoring/REFERENCES.md` ## Status -Protected `develop` includes the employment-truth kernel, governed candidate-to-worker conversion, purpose-bound PII authorization, normalized worker-bound validity studies, criterion-observation scope, bitemporal workforce-composition evidence, the governed Naruon intent adapter, and requisition review packets. This active PR adds durable purpose-bound People mutation and confirmed-hire materialization paths for Employment, Position, and Assignment with atomic audit/outbox evidence and tenant-scoped idempotency; treat those write paths as active-PR truth until this exact head passes all fresh protected-base gates and merges. +Protected `develop` at `9e3e4847510e1e612b48474ba42b177b8ed824df` includes the employment-truth kernel, governed candidate-to-worker conversion, purpose-bound PII authorization, normalized worker-bound validity studies, criterion-observation scope, the governed Naruon intent adapter, requisition review packets, the governed People mutation/confirmed-hire implementation with tenant-scoped idempotency and atomic audit/outbox evidence, and canonical persisted Job Analysis through migration `0013` and the protected Job Analysis API. Workforce-composition evidence remains active PR #54 rather than protected truth. The next protected product gaps are a connected and released browser workspace, statistical validity estimation, and a versioned release; see `docs/product-technical-gap-baseline.md` for exact evidence boundaries and current PR state. diff --git a/apps/hr-workspace/app.js b/apps/hr-workspace/app.js new file mode 100644 index 000000000..ba645622a --- /dev/null +++ b/apps/hr-workspace/app.js @@ -0,0 +1,446 @@ +const translations = { + en: { + productLabel: 'Evidence-centered HRIS', workspaceLabel: 'People workspace', apiBoundary: 'Protected People API boundary: not connected in this fixture', fixtureMode: 'Local fixture mode', hrHome: 'HR Home', employeeProfile: 'Employee Profile', fixtureBadge: 'Fixture evidence', hrHomeBreadcrumb: 'Orgmetra / HR Home', employeeProfileBreadcrumb: 'Orgmetra / Employee Profile', today: 'Today', hiringReview: 'hiring decisions need evidence review', positionChanges: 'position changes effective next week', validationApproval: 'validation study needs approval', workQueue: 'Work queue', nextActions: 'Next actions', reviewEvidence: 'Review evidence', reviewEvidenceDetail: 'Approve or return a decision packet', effectiveConflicts: 'Effective-date conflicts', effectiveConflictsDetail: 'Inspect the employee history timeline', validityStudy: 'Open validity study', validityStudyDetail: 'Review the supporting evidence versions', evidenceState: 'Evidence state', readyForReview: 'Ready for human review', reviewState: 'Review', reviewCopy: 'Orgmetra keeps the actor, purpose, reason, and evidence versions visible before a high-impact action.', actor: 'Actor', purpose: 'Purpose', source: 'Source', personSummary: 'Person summary', sampleEmployee: 'Sample employee', syntheticRecord: 'Synthetic record for local interaction proof', authorized: 'HR operations access', person: 'Person', personValue: 'Identity and name facts', employment: 'Employment', employmentValue: 'Worker relationship', position: 'Position', positionValue: 'AI Product Architect', assignment: 'Assignment', assignmentValue: 'Platform 60% · Governance 40%', accessPurpose: 'Access purpose', hrOperations: 'HR operations', recruiting: 'Recruiting', viewPersonalDetails: 'View personal details', correctHistory: 'Correct history', permissionDenied: 'Permission denied', permissionDeniedCopy: 'This purpose does not authorize personal details. Choose a permitted HR purpose or request access.', detailsVisible: 'Personal details visible', detailsVisibleCopy: 'Purpose-bound access was evaluated for this fixture and recorded for audit.', bitemporalHistory: 'Bitemporal history', historyTitle: 'Effective vs recorded time', readOnly: 'Read-only snapshot', historyCaption: 'Employee history with effective and recorded time', record: 'Record', effectiveTime: 'Effective time', recordedTime: 'Recorded time', state: 'State', active: 'Active', pendingReview: 'Pending review', assignmentSplit: 'Assignment split', capacityTitle: 'Visible allocation capacity', assignmentCaption: 'Exact assignment allocation values', assignmentName: 'Assignment', allocation: 'Allocation', nextAction: 'Next action', noAction: 'No action required', credentialBoundary: 'Credential boundary', credentialCopy: 'No identity credential or passkey is stored in the person record.', evidenceDrawer: 'Evidence drawer', evidenceTitle: 'Decision packet evidence', evidenceCopy: 'These references are reviewable inputs. They do not make an autonomous employment decision.', evidenceOne: 'Structured interview criterion ratings', evidenceTwo: 'SME-approved job profile version 4', evidenceThree: 'Human reviewer reason and purpose record', close: 'Close', changeLanguage: 'Change language to 한국어', requestEvidence: 'Request more evidence', highImpactConfirmation: 'High-impact confirmation', correctHistoryTitle: 'Correct history', confirmationCopy: 'A correction remains a draft until a human confirms the actor, purpose, reason, and evidence context.', reason: 'Reason', reasonPlaceholder: 'Required', draftConfirmed: 'Draft correction confirmed for local fixture evidence; no API mutation was sent.', cancel: 'Cancel', confirm: 'Confirm correction' + }, + ko: { + productLabel: '근거 중심 HRIS', workspaceLabel: '사람 워크스페이스', apiBoundary: '보호된 People API 경계: 이 픽스처에서는 연결되지 않음', fixtureMode: '로컬 픽스처 모드', hrHome: 'HR 홈', employeeProfile: '직원 프로필', fixtureBadge: '픽스처 근거', hrHomeBreadcrumb: 'Orgmetra / HR 홈', employeeProfileBreadcrumb: 'Orgmetra / 직원 프로필', today: '오늘', hiringReview: '근거 검토가 필요한 채용 결정', positionChanges: '다음 주 효력이 시작되는 직위 변경', validationApproval: '승인이 필요한 타당도 연구', workQueue: '작업 큐', nextActions: '다음 작업', reviewEvidence: '근거 검토', reviewEvidenceDetail: '결정 패킷을 승인하거나 반환', effectiveConflicts: '효력일 충돌', effectiveConflictsDetail: '직원 이력 타임라인 확인', validityStudy: '타당도 연구 열기', validityStudyDetail: '지원 근거 버전 검토', evidenceState: '근거 상태', readyForReview: '사람 검토 대기', reviewState: '검토', reviewCopy: '고위험 작업 전에 행위자, 목적, 사유, 근거 버전을 표시합니다.', actor: '행위자', purpose: '목적', source: '출처', personSummary: '사람 요약', sampleEmployee: '샘플 직원', syntheticRecord: '로컬 상호작용 증명을 위한 합성 레코드', authorized: 'HR 운영 접근', person: '사람', personValue: '식별 및 이름 사실', employment: '고용', employmentValue: '근로자 관계', position: '직위', positionValue: 'AI 제품 아키텍트', assignment: '배정', assignmentValue: '플랫폼 60% · 거버넌스 40%', accessPurpose: '접근 목적', hrOperations: 'HR 운영', recruiting: '채용', viewPersonalDetails: '개인 상세 보기', correctHistory: '이력 정정', permissionDenied: '권한 거부', permissionDeniedCopy: '이 목적에는 개인 상세 접근 권한이 없습니다. 허용된 HR 목적을 선택하거나 접근을 요청하세요.', detailsVisible: '개인 상세 표시', detailsVisibleCopy: '이 픽스처의 목적 기반 접근을 평가하고 감사 기록을 남겼습니다.', bitemporalHistory: '이중 시간 이력', historyTitle: '효력 시간과 기록 시간', readOnly: '읽기 전용 스냅샷', historyCaption: '효력 시간과 기록 시간을 포함한 직원 이력', record: '레코드', effectiveTime: '효력 시간', recordedTime: '기록 시간', state: '상태', active: '활성', pendingReview: '검토 대기', assignmentSplit: '배정 비율', capacityTitle: '표시된 할당 용량', assignmentCaption: '정확한 배정 할당 값', assignmentName: '배정', allocation: '할당', nextAction: '다음 작업', noAction: '조치 필요 없음', credentialBoundary: '자격 증명 경계', credentialCopy: '사람 레코드에 신원 자격 증명이나 패스키를 저장하지 않습니다.', evidenceDrawer: '근거 서랍', evidenceTitle: '결정 패킷 근거', evidenceCopy: '검토 가능한 입력이며 자율적인 고용 결정을 만들지 않습니다.', evidenceOne: '구조화 면접 기준 평정', evidenceTwo: 'SME 승인 직무 프로필 버전 4', evidenceThree: '사람 검토자의 사유 및 목적 기록', close: '닫기', changeLanguage: '언어를 English로 변경', requestEvidence: '추가 근거 요청', highImpactConfirmation: '고위험 작업 확인', correctHistoryTitle: '이력 정정', confirmationCopy: '행위자, 목적, 사유, 근거 맥락을 사람이 확인하기 전까지 정정은 초안으로 남습니다.', reason: '사유', reasonPlaceholder: '필수', draftConfirmed: '로컬 픽스처 근거에 정정 초안을 확인했으며 API 변경은 전송하지 않았습니다.', cancel: '취소', confirm: '정정 확인' + } +}; + +Object.assign(translations.en, { + jobAnalysis: 'Job Analysis', + jobAnalysisBadge: 'API-bound read', + jobAnalysisBreadcrumb: 'Orgmetra / Job Analysis', + jobAnalysisTitle: 'Job Analysis snapshot', + jobAnalysisCopy: 'Read one governed, bitemporal job-analysis snapshot from the protected API.', + jobAnalysisTenant: 'Tenant record ID', + jobAnalysisRecord: 'Analysis record ID', + jobAnalysisPurpose: 'Purpose code', + jobAnalysisLoad: 'Load snapshot', + jobAnalysisReady: 'Ready to request a protected snapshot.', + jobAnalysisNotConfigured: 'Not connected: the host must provide an API base URL and authorization provider.', + jobAnalysisLoading: 'Loading governed snapshot…', + jobAnalysisLoaded: 'Snapshot loaded from the protected Job Analysis API.', + jobAnalysisDenied: 'The protected API denied this request. Verify the purpose and host authorization.', + jobAnalysisFailed: 'The protected API could not return this snapshot. No local fallback was used.', + jobAnalysisSummary: 'Snapshot evidence', + jobAnalysisAnalysisId: 'Analysis record', + jobAnalysisStatus: 'Status', + jobAnalysisEffective: 'Effective from', + jobAnalysisRecorded: 'Recorded at', + jobAnalysisDigest: 'Content digest', + jobAnalysisTasks: 'Tasks', + jobAnalysisKsaos: 'KSAO requirements', + jobAnalysisNoValues: 'No snapshot values loaded.', + peopleApiBadge: 'API-bound read', + peopleApiTitle: 'Protected People record', + peopleApiCopy: 'Read one authorized worker record from the protected People API.', + peopleApiTenant: 'Tenant record ID', + peopleApiPerson: 'Person record ID', + peopleApiEffective: 'Effective date', + peopleApiPurpose: 'Purpose code', + peopleApiFields: 'Requested fields', + peopleApiLoad: 'Load worker record', + peopleApiReady: 'Ready to request a protected worker record.', + peopleApiNotConfigured: 'Not connected: the host must provide a People API URL and authorization provider.', + peopleApiLoading: 'Loading the authorized worker record…', + peopleApiLoaded: 'Worker record loaded from the protected People API.', + peopleApiDenied: 'The protected People API denied this request. Verify purpose and authorization.', + peopleApiFailed: 'The protected People API could not return this record. No local fallback was used.', + peopleApiDisplayName: 'Authorized display name', + peopleApiEmploymentStatus: 'Employment status', + peopleApiNoValues: 'No protected People API values loaded.', +}); +Object.assign(translations.ko, { + jobAnalysis: '직무 분석', + jobAnalysisBadge: 'API 연결 읽기', + jobAnalysisBreadcrumb: 'Orgmetra / 직무 분석', + jobAnalysisTitle: '직무 분석 스냅샷', + jobAnalysisCopy: '보호된 API에서 하나의 거버넌스 적용 이중 시간 직무 분석 스냅샷을 읽습니다.', + jobAnalysisTenant: '테넌트 레코드 ID', + jobAnalysisRecord: '분석 레코드 ID', + jobAnalysisPurpose: '목적 코드', + jobAnalysisLoad: '스냅샷 불러오기', + jobAnalysisReady: '보호된 스냅샷을 요청할 준비가 되었습니다.', + jobAnalysisNotConfigured: '연결되지 않음: 호스트가 API 기본 URL과 인증 제공자를 제공해야 합니다.', + jobAnalysisLoading: '거버넌스 적용 스냅샷을 불러오는 중…', + jobAnalysisLoaded: '보호된 직무 분석 API에서 스냅샷을 불러왔습니다.', + jobAnalysisDenied: '보호된 API가 요청을 거부했습니다. 목적과 호스트 인증을 확인하세요.', + jobAnalysisFailed: '보호된 API에서 이 스냅샷을 반환하지 못했습니다. 로컬 대체 데이터는 사용하지 않았습니다.', + jobAnalysisSummary: '스냅샷 근거', + jobAnalysisAnalysisId: '분석 레코드', + jobAnalysisStatus: '상태', + jobAnalysisEffective: '효력 시작일', + jobAnalysisRecorded: '기록 시각', + jobAnalysisDigest: '콘텐츠 다이제스트', + jobAnalysisTasks: '과업', + jobAnalysisKsaos: 'KSAO 요구사항', + jobAnalysisNoValues: '불러온 스냅샷 값이 없습니다.', + peopleApiBadge: 'API 연결 읽기', + peopleApiTitle: '보호된 People 레코드', + peopleApiCopy: '보호된 People API에서 권한이 부여된 근로자 레코드 하나를 읽습니다.', + peopleApiTenant: '테넌트 레코드 ID', + peopleApiPerson: '사람 레코드 ID', + peopleApiEffective: '효력 기준일', + peopleApiPurpose: '목적 코드', + peopleApiFields: '요청 필드', + peopleApiLoad: '근로자 레코드 불러오기', + peopleApiReady: '보호된 근로자 레코드를 요청할 준비가 되었습니다.', + peopleApiNotConfigured: '연결되지 않음: 호스트가 People API URL과 인증 제공자를 제공해야 합니다.', + peopleApiLoading: '권한이 부여된 근로자 레코드를 불러오는 중…', + peopleApiLoaded: '보호된 People API에서 근로자 레코드를 불러왔습니다.', + peopleApiDenied: '보호된 People API가 요청을 거부했습니다. 목적과 인증을 확인하세요.', + peopleApiFailed: '보호된 People API에서 레코드를 반환하지 못했습니다. 로컬 대체 데이터는 사용하지 않았습니다.', + peopleApiDisplayName: '권한이 부여된 표시 이름', + peopleApiEmploymentStatus: '고용 상태', + peopleApiNoValues: '불러온 보호된 People API 값이 없습니다.', +}); + +/** + * Return whether the selected purpose is allowed to reveal personal details. + * @param {string} purpose Purpose code selected by the reviewer. + * @returns {boolean} True only for the fixture's HR-operations purpose. + */ +export function isPurposeAuthorized(purpose) { + return purpose === 'hr_operations'; +} + +/** + * Return the alternate supported workspace locale. + * @param {string} locale Current locale code. + * @returns {'en'|'ko'} The other supported locale; unknown values fall back to English. + */ +export function nextLocale(locale) { + return locale === 'en' ? 'ko' : 'en'; +} + +/** + * Build the protected Job Analysis snapshot URL after validating required identifiers. + * @param {{baseUrl: string, tenantRecordId: string, analysisRecordId: string}} config Request coordinates. + * @returns {string} Encoded snapshot URL. + * @throws {Error} If the base URL, tenant record ID, or analysis record ID is missing. + */ +export function jobAnalysisSnapshotUrl(config) { + if (!config || typeof config.baseUrl !== 'string' || !config.baseUrl.trim()) { + throw new Error('Job Analysis API base URL is not configured.'); + } + if (typeof config.tenantRecordId !== 'string' || !config.tenantRecordId.trim()) { + throw new Error('Tenant record ID is required.'); + } + if (typeof config.analysisRecordId !== 'string' || !config.analysisRecordId.trim()) { + throw new Error('Analysis record ID is required.'); + } + return `${config.baseUrl.replace(/\/$/, '')}/v1/tenants/${encodeURIComponent(config.tenantRecordId)}/job-analysis-snapshots/${encodeURIComponent(config.analysisRecordId)}`; +} + +/** + * Read one protected Job Analysis snapshot using a host-provided short-lived credential. + * The credential is used only for this request and is never persisted by the workspace. + * @param {{getAuthorization: Function, purposeCode?: string} & Record} config Protected-read configuration. + * @param {typeof fetch} fetchImpl Fetch implementation, injectable for tests. + * @returns {Promise} Parsed snapshot payload. + * @throws {Error} For missing authorization providers/credentials, unavailable fetch, denied access, or failed requests. + */ +export async function fetchJobAnalysisSnapshot(config, fetchImpl = globalThis.fetch) { + if (typeof config?.getAuthorization !== 'function') { + throw new Error('Job Analysis API authorization provider is not configured.'); + } + if (typeof fetchImpl !== 'function') throw new Error('Fetch is unavailable.'); + const authorization = await config.getAuthorization(); + if (typeof authorization !== 'string' || !authorization.trim()) { + throw new Error('Job Analysis API authorization provider returned no credential.'); + } + const response = await fetchImpl(jobAnalysisSnapshotUrl(config), { + headers: { + Authorization: authorization, + 'X-Purpose-Code': config.purposeCode || 'job_analysis_read', + }, + credentials: 'omit', + }); + if (response.status === 401 || response.status === 403) throw new Error('JOB_ANALYSIS_ACCESS_DENIED'); + if (!response.ok) throw new Error('JOB_ANALYSIS_REQUEST_FAILED'); + return response.json(); +} + +/** + * Build the protected People-record URL after validating required read coordinates. + * @param {{baseUrl: string, tenantRecordId: string, personRecordId: string, effectiveOn: string, purposeCode?: string, requestedFields?: string[]}} config Request coordinates. + * @returns {string} Encoded People API URL with effective-date, purpose, and field query parameters. + * @throws {Error} If required coordinates or requested fields are invalid. + */ +export function peopleRecordUrl(config) { + if (!config || typeof config.baseUrl !== 'string' || !config.baseUrl.trim()) { + throw new Error('People API base URL is not configured.'); + } + if (typeof config.tenantRecordId !== 'string' || !config.tenantRecordId.trim()) { + throw new Error('Tenant record ID is required.'); + } + if (typeof config.personRecordId !== 'string' || !config.personRecordId.trim()) { + throw new Error('Person record ID is required.'); + } + if (typeof config.effectiveOn !== 'string' || !config.effectiveOn.trim()) { + throw new Error('Effective date is required.'); + } + const fields = Array.isArray(config.requestedFields) ? config.requestedFields : ['display_name', 'employment_status_code']; + if (!fields.length || fields.some((field) => typeof field !== 'string' || !field.trim())) { + throw new Error('At least one requested People API field is required.'); + } + const query = new URLSearchParams({ + effective_on: config.effectiveOn, + purpose: config.purposeCode || 'people_read', + fields: fields.join(','), + }); + return `${config.baseUrl.replace(/\/$/, '')}/v1/tenants/${encodeURIComponent(config.tenantRecordId)}/people/${encodeURIComponent(config.personRecordId)}?${query}`; +} + +/** + * Read one protected People record using a host-provided short-lived credential. + * The credential is used only for this request and is never persisted by the workspace. + * @param {{getAuthorization: Function} & Record} config Protected-read configuration. + * @param {typeof fetch} fetchImpl Fetch implementation, injectable for tests. + * @returns {Promise} Parsed People record payload. + * @throws {Error} For missing authorization providers/credentials, unavailable fetch, denied access, or failed requests. + */ +export async function fetchPeopleRecord(config, fetchImpl = globalThis.fetch) { + if (typeof config?.getAuthorization !== 'function') { + throw new Error('People API authorization provider is not configured.'); + } + if (typeof fetchImpl !== 'function') throw new Error('Fetch is unavailable.'); + const authorization = await config.getAuthorization(); + if (typeof authorization !== 'string' || !authorization.trim()) { + throw new Error('People API authorization provider returned no credential.'); + } + const response = await fetchImpl(peopleRecordUrl(config), { + headers: { Authorization: authorization }, + credentials: 'omit', + }); + if (response.status === 401 || response.status === 403) throw new Error('PEOPLE_ACCESS_DENIED'); + if (!response.ok) throw new Error('PEOPLE_REQUEST_FAILED'); + return response.json(); +} + +function setLocale(locale) { + const dictionary = translations[locale]; + document.documentElement.lang = locale; + document.documentElement.dataset.locale = locale; + document.querySelectorAll('[data-i18n]').forEach((element) => { + const value = dictionary[element.dataset.i18n]; + if (value) element.textContent = value; + }); + document.querySelectorAll('[data-i18n-placeholder]').forEach((element) => { + const value = dictionary[element.dataset.i18nPlaceholder]; + if (value) element.placeholder = value; + }); + document.querySelectorAll('[data-i18n-aria-label]').forEach((element) => { + const value = dictionary[element.dataset.i18nAriaLabel]; + if (value) element.setAttribute('aria-label', value); + }); + document.getElementById('locale-toggle').textContent = locale === 'en' ? '한국어' : 'English'; +} + +function activateView(viewName) { + document.querySelectorAll('[data-view]').forEach((view) => { + const active = view.dataset.view === viewName; + view.hidden = !active; + view.classList.toggle('is-hidden', !active); + }); + document.querySelectorAll('[data-view-link]').forEach((link) => { + const active = link.dataset.viewLink === viewName; + link.classList.toggle('is-active', active); + if (link.matches('button')) { + if (active) link.setAttribute('aria-current', 'page'); + else link.removeAttribute('aria-current'); + } + }); + document.getElementById('main-content').focus({ preventScroll: true }); +} + +function openDialog(id) { + const dialog = document.getElementById(id); + if (typeof dialog.showModal === 'function') dialog.showModal(); + else dialog.hidden = false; +} + +function closeDialog(id) { + const dialog = document.getElementById(id); + if (typeof dialog.close === 'function') dialog.close(); + else dialog.hidden = true; +} + +function resetConfirmationState() { + document.getElementById('confirmation-reason').value = ''; + document.getElementById('confirmation-status').hidden = true; +} + +function jobAnalysisMessage(key) { + return translations[document.documentElement.dataset.locale || 'en'][key]; +} + +function setJobAnalysisStatus(key, state = 'idle') { + const status = document.getElementById('job-analysis-status'); + status.dataset.i18n = key; + status.dataset.state = state; + status.textContent = jobAnalysisMessage(key); +} + +function clearJobAnalysisSnapshot() { + document.getElementById('job-analysis-result').hidden = true; + document.getElementById('job-analysis-analysis-id').textContent = 'unknown'; + document.getElementById('job-analysis-state').textContent = 'unknown'; + document.getElementById('job-analysis-effective').textContent = 'unknown'; + document.getElementById('job-analysis-recorded').textContent = 'unknown'; + document.getElementById('job-analysis-digest').textContent = 'unknown'; + document.getElementById('job-analysis-task-count').textContent = '0'; + document.getElementById('job-analysis-ksao-count').textContent = '0'; +} + +function renderJobAnalysisSnapshot(snapshot) { + const result = document.getElementById('job-analysis-result'); + const tasks = Array.isArray(snapshot?.tasks) ? snapshot.tasks : []; + const ksaos = Array.isArray(snapshot?.ksao_requirements) ? snapshot.ksao_requirements : []; + document.getElementById('job-analysis-analysis-id').textContent = snapshot?.analysis_record_id || 'unknown'; + document.getElementById('job-analysis-state').textContent = snapshot?.status_code || 'unknown'; + document.getElementById('job-analysis-effective').textContent = snapshot?.effective_from || 'unknown'; + document.getElementById('job-analysis-recorded').textContent = snapshot?.recorded_at || 'unknown'; + document.getElementById('job-analysis-digest').textContent = snapshot?.content_digest_sha256 || 'unknown'; + document.getElementById('job-analysis-task-count').textContent = String(tasks.length); + document.getElementById('job-analysis-ksao-count').textContent = String(ksaos.length); + result.hidden = false; +} + +function peopleApiMessage(key) { + return translations[document.documentElement.dataset.locale || 'en'][key]; +} + +function setPeopleApiStatus(key, state = 'idle') { + const status = document.getElementById('people-api-status'); + status.dataset.i18n = key; + status.dataset.state = state; + status.textContent = peopleApiMessage(key); +} + +function clearPeopleRecord() { + document.getElementById('people-api-result').hidden = true; + document.getElementById('people-api-display-name').textContent = 'unknown'; + document.getElementById('people-api-employment-status').textContent = 'unknown'; +} + +function renderPeopleRecord(payload) { + const fields = payload?.fields; + if (!fields || typeof fields !== 'object') throw new Error('PEOPLE_REQUEST_FAILED'); + document.getElementById('people-api-display-name').textContent = fields.display_name || 'unknown'; + document.getElementById('people-api-employment-status').textContent = fields.employment_status_code || 'unknown'; + document.getElementById('people-api-result').hidden = false; +} + +if (typeof document !== 'undefined') { + let locale = 'en'; + let jobAnalysisRequestVersion = 0; + let peopleApiRequestVersion = 0; + document.querySelectorAll('[data-view-link]').forEach((link) => link.addEventListener('click', () => activateView(link.dataset.viewLink))); + document.getElementById('locale-toggle').addEventListener('click', () => { + locale = nextLocale(locale); + setLocale(locale); + }); + document.querySelectorAll('[data-open-dialog]').forEach((button) => button.addEventListener('click', () => openDialog(button.dataset.openDialog))); + document.querySelectorAll('[data-close-dialog]').forEach((button) => button.addEventListener('click', () => closeDialog(button.dataset.closeDialog))); + document.querySelector('[data-action="view-personal-details"]').addEventListener('click', () => { + const authorized = isPurposeAuthorized(document.getElementById('access-purpose').value); + document.getElementById('permission-panel').hidden = authorized; + document.getElementById('details-panel').hidden = !authorized; + }); + document.querySelector('[data-action="correct-history"]').addEventListener('click', () => { + resetConfirmationState(); + openDialog('confirmation-dialog'); + }); + document.getElementById('confirmation-form').addEventListener('submit', (event) => { + if (event.submitter?.value !== 'confirm') return; + const reason = document.getElementById('confirmation-reason'); + if (!reason.value.trim()) { + event.preventDefault(); + reason.focus(); + return; + } + event.preventDefault(); + document.getElementById('confirmation-status').hidden = false; + }); + const jobAnalysisForm = document.getElementById('job-analysis-form'); + const jobAnalysisConfig = globalThis.__ORGMETRA_JOB_ANALYSIS__; + if (jobAnalysisConfig?.tenantRecordId) document.getElementById('job-analysis-tenant').value = jobAnalysisConfig.tenantRecordId; + if (jobAnalysisConfig?.analysisRecordId) document.getElementById('job-analysis-record').value = jobAnalysisConfig.analysisRecordId; + if (jobAnalysisConfig?.purposeCode) document.getElementById('job-analysis-purpose').value = jobAnalysisConfig.purposeCode; + if (!jobAnalysisConfig?.baseUrl || typeof jobAnalysisConfig?.getAuthorization !== 'function') { + setJobAnalysisStatus('jobAnalysisNotConfigured', 'not-configured'); + } else { + setJobAnalysisStatus('jobAnalysisReady'); + } + jobAnalysisForm.addEventListener('submit', async (event) => { + event.preventDefault(); + if (!jobAnalysisConfig?.baseUrl || typeof jobAnalysisConfig?.getAuthorization !== 'function') { + clearJobAnalysisSnapshot(); + setJobAnalysisStatus('jobAnalysisNotConfigured', 'not-configured'); + return; + } + const requestVersion = ++jobAnalysisRequestVersion; + clearJobAnalysisSnapshot(); + const config = { + ...(jobAnalysisConfig || {}), + tenantRecordId: document.getElementById('job-analysis-tenant').value, + analysisRecordId: document.getElementById('job-analysis-record').value, + purposeCode: document.getElementById('job-analysis-purpose').value, + }; + setJobAnalysisStatus('jobAnalysisLoading', 'loading'); + try { + const snapshot = await fetchJobAnalysisSnapshot(config); + if (requestVersion !== jobAnalysisRequestVersion) return; + renderJobAnalysisSnapshot(snapshot); + setJobAnalysisStatus('jobAnalysisLoaded', 'loaded'); + } catch (error) { + if (requestVersion !== jobAnalysisRequestVersion) return; + clearJobAnalysisSnapshot(); + setJobAnalysisStatus(error.message === 'JOB_ANALYSIS_ACCESS_DENIED' ? 'jobAnalysisDenied' : 'jobAnalysisFailed', 'error'); + } + }); + const peopleApiForm = document.getElementById('people-api-form'); + const peopleApiConfig = globalThis.__ORGMETRA_PEOPLE__; + if (peopleApiConfig?.tenantRecordId) document.getElementById('people-api-tenant').value = peopleApiConfig.tenantRecordId; + if (peopleApiConfig?.personRecordId) document.getElementById('people-api-person').value = peopleApiConfig.personRecordId; + if (peopleApiConfig?.effectiveOn) document.getElementById('people-api-effective').value = peopleApiConfig.effectiveOn; + if (peopleApiConfig?.purposeCode) document.getElementById('people-api-purpose').value = peopleApiConfig.purposeCode; + if (Array.isArray(peopleApiConfig?.requestedFields)) document.getElementById('people-api-fields').value = peopleApiConfig.requestedFields.join(','); + if (!peopleApiConfig?.baseUrl || typeof peopleApiConfig?.getAuthorization !== 'function') { + setPeopleApiStatus('peopleApiNotConfigured', 'not-configured'); + } else { + setPeopleApiStatus('peopleApiReady'); + } + peopleApiForm.addEventListener('submit', async (event) => { + event.preventDefault(); + if (!peopleApiConfig?.baseUrl || typeof peopleApiConfig?.getAuthorization !== 'function') { + clearPeopleRecord(); + setPeopleApiStatus('peopleApiNotConfigured', 'not-configured'); + return; + } + const requestVersion = ++peopleApiRequestVersion; + clearPeopleRecord(); + const config = { + ...(peopleApiConfig || {}), + tenantRecordId: document.getElementById('people-api-tenant').value, + personRecordId: document.getElementById('people-api-person').value, + effectiveOn: document.getElementById('people-api-effective').value, + purposeCode: document.getElementById('people-api-purpose').value, + requestedFields: document.getElementById('people-api-fields').value.split(',').map((field) => field.trim()), + }; + setPeopleApiStatus('peopleApiLoading', 'loading'); + try { + const record = await fetchPeopleRecord(config); + if (requestVersion !== peopleApiRequestVersion) return; + renderPeopleRecord(record); + setPeopleApiStatus('peopleApiLoaded', 'loaded'); + } catch (error) { + if (requestVersion !== peopleApiRequestVersion) return; + clearPeopleRecord(); + setPeopleApiStatus(error.message === 'PEOPLE_ACCESS_DENIED' ? 'peopleApiDenied' : 'peopleApiFailed', 'error'); + } + }); + setLocale(locale); +} \ No newline at end of file diff --git a/apps/hr-workspace/index.html b/apps/hr-workspace/index.html new file mode 100644 index 000000000..6b4a330d2 --- /dev/null +++ b/apps/hr-workspace/index.html @@ -0,0 +1,160 @@ + + + + + + + Orgmetra HR workspace + + + + + + +
+ + +
+
+
+

People workspace

+

Protected People API boundary: not connected in this fixture

+
+ +
+ +
+
+

HR Home

+ Fixture evidence +
+
+

Today

+
    +
  • 3 hiring decisions need evidence review
  • +
  • 2 position changes effective next week
  • +
  • 1 validation study needs approval
  • +
+
+
+
+

Work queue

Next actions

3
+
+ + + +
+
+
+

Evidence state

Ready for human review

Review
+

Orgmetra keeps the actor, purpose, reason, and evidence versions visible before a high-impact action.

+
ActorHR operations reviewer
PurposeHR operations
SourceProtected People API contract
+
+
+
+ + + + +
+
+ + +

Evidence drawer

Decision packet evidence

+

These references are reviewable inputs. They do not make an autonomous employment decision.

+
  • EV-2026-014Structured interview criterion ratings
  • EV-2026-021SME-approved job profile version 4
  • EV-2026-027Human reviewer reason and purpose record
+
+
+ + +
+

High-impact confirmation

Correct history

+

A correction remains a draft until a human confirms the actor, purpose, reason, and evidence context.

+
+ +
+
+
+ + \ No newline at end of file diff --git a/apps/hr-workspace/styles.css b/apps/hr-workspace/styles.css new file mode 100644 index 000000000..adfc9d666 --- /dev/null +++ b/apps/hr-workspace/styles.css @@ -0,0 +1,122 @@ +:root { + --workspace-sidebar: #0f172a; + --workspace-sidebar-muted: #aeb9ca; + --workspace-shadow: 0 18px 45px rgba(15, 23, 42, 0.08); +} + +* { box-sizing: border-box; } +body { margin: 0; background: var(--orgmetra-surface-page); color: var(--orgmetra-text-primary); font: 16px/1.5 "Source Sans 3", system-ui, sans-serif; } +button, input, select, textarea { font: inherit; } +button { cursor: pointer; } +button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid var(--orgmetra-focus-ring); outline-offset: 2px; } +.skip-link { position: fixed; top: var(--orgmetra-space-sm); left: var(--orgmetra-space-sm); z-index: 1000; transform: translateY(calc(-100% - var(--orgmetra-space-lg))); border: 2px solid var(--orgmetra-action-review); border-radius: var(--orgmetra-radius-md); padding: 10px 14px; background: var(--orgmetra-surface-card); color: var(--orgmetra-text-primary); font-weight: 700; text-decoration: none; } +.skip-link:focus, .skip-link:focus-visible { transform: translateY(0); } +html[lang="en"] .skip-link [lang="ko"], html[lang="ko"] .skip-link [lang="en"] { display: none; } +.app-shell { min-height: 100vh; display: grid; grid-template-columns: 232px minmax(0, 1fr); } +.sidebar { display: flex; flex-direction: column; gap: var(--orgmetra-space-md); padding: 32px 20px; background: var(--workspace-sidebar); color: white; } +.brand { color: white; font-size: 24px; font-weight: 700; text-decoration: none; letter-spacing: -0.02em; } +.eyebrow { margin: 0; color: var(--orgmetra-text-muted); font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; } +.sidebar .eyebrow { color: var(--workspace-sidebar-muted); } +.nav-list { display: grid; gap: var(--orgmetra-space-xs); margin-top: var(--orgmetra-space-lg); } +.nav-item { width: 100%; border: 0; border-radius: var(--orgmetra-radius-md); padding: 11px 12px; background: transparent; color: var(--workspace-sidebar-muted); text-align: left; } +.nav-item:hover, .nav-item.is-active { background: rgba(255, 255, 255, 0.12); color: white; } +.sidebar-note { display: flex; align-items: center; gap: var(--orgmetra-space-sm); margin-top: auto; color: var(--workspace-sidebar-muted); font-size: 13px; } +.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--orgmetra-action-approve); } +.main-content { min-width: 0; padding: 28px clamp(20px, 4vw, 64px) 64px; } +.topbar { display: flex; align-items: center; justify-content: space-between; gap: var(--orgmetra-space-md); max-width: 1180px; margin: 0 auto 48px; } +.topbar-status { margin: 2px 0 0; color: var(--orgmetra-text-muted); font-size: 13px; } +.view { max-width: 1180px; margin: 0 auto; } +[hidden] { display: none !important; } +.view.is-hidden { display: none; } +.view-heading, .profile-heading, .panel-heading, .dialog-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--orgmetra-space-md); } +h1, h2, p { margin-top: 0; } +h1 { margin-bottom: 0; font-size: clamp(28px, 4vw, 42px); line-height: 1.1; letter-spacing: -0.03em; } +h2 { margin-bottom: 0; font-size: 20px; line-height: 1.2; letter-spacing: -0.015em; } +.breadcrumb { margin: 0 0 var(--orgmetra-space-sm); color: var(--orgmetra-text-muted); font-size: 13px; } +.badge, .count-badge { display: inline-flex; align-items: center; min-height: 26px; border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 700; white-space: nowrap; } +.badge-fixture { background: #e2e8f0; color: var(--orgmetra-action-export); } +.badge-review { background: #dbeafe; color: var(--orgmetra-action-review); } +.badge-authorized { background: #dcfce7; color: var(--orgmetra-action-approve); } +.badge-neutral { background: #eef2f7; color: var(--orgmetra-text-muted); } +.count-badge { background: #e0e7ff; color: var(--orgmetra-action-review); } +.summary-card, .profile-card, .panel { border: 1px solid var(--orgmetra-border-subtle); border-radius: 14px; background: var(--orgmetra-surface-card); box-shadow: var(--workspace-shadow); } +.summary-card { margin-top: 28px; padding: 26px; } +.summary-lead { margin-bottom: 2px; font-size: 20px; font-weight: 600; } +.summary-list { display: grid; gap: 4px; margin: 0; padding-left: 20px; color: var(--orgmetra-text-primary); } +.summary-list strong { font-variant-numeric: tabular-nums; } +.section-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--orgmetra-space-lg); margin-top: var(--orgmetra-space-lg); } +.panel, .profile-card { padding: 24px; } +.panel-accent-review { border-top: 4px solid var(--orgmetra-action-review); } +.panel-heading { margin-bottom: 20px; } +.panel-heading .eyebrow { margin-bottom: 4px; } +.panel-copy { color: var(--orgmetra-text-muted); } +.action-list { display: grid; gap: var(--orgmetra-space-sm); } +.action-row { display: flex; align-items: center; justify-content: space-between; gap: var(--orgmetra-space-md); width: 100%; border: 1px solid transparent; border-radius: var(--orgmetra-radius-md); padding: 12px; background: rgba(255, 255, 255, 0.8); color: inherit; text-align: left; } +.action-row:hover { border-color: var(--orgmetra-action-review); background: white; } +.action-row strong, .action-row small { display: block; } +.action-row small { margin-top: 2px; color: var(--orgmetra-text-muted); } +.fact-list { display: grid; gap: 1px; overflow: hidden; border: 1px solid var(--orgmetra-border-subtle); border-radius: var(--orgmetra-radius-md); } +.fact-list div { display: flex; justify-content: space-between; gap: var(--orgmetra-space-md); padding: 10px 12px; background: white; } +.fact-list span { color: var(--orgmetra-text-muted); } +.profile-card { margin-top: 28px; } +.profile-heading { align-items: center; margin-bottom: 24px; } +.profile-heading h2 { margin-bottom: 4px; font-size: 28px; } +.muted, .helper-text { margin-bottom: 0; color: var(--orgmetra-text-muted); } +.concept-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--orgmetra-space-sm); } +.concept-card { display: grid; gap: 3px; min-width: 0; border: 1px solid var(--orgmetra-border-subtle); border-radius: var(--orgmetra-radius-md); padding: 14px; background: white; } +.concept-card span { color: var(--orgmetra-text-muted); font-size: 13px; } +.concept-card strong { overflow-wrap: anywhere; font-size: 14px; } +.concept-card small { color: var(--orgmetra-text-muted); font-size: 13px; } +.profile-toolbar { display: flex; align-items: end; justify-content: space-between; gap: var(--orgmetra-space-md); margin: var(--orgmetra-space-lg) 0; } +.field-label { display: grid; gap: 6px; color: var(--orgmetra-text-muted); font-size: 13px; font-weight: 700; } +.select-field, input, textarea { min-height: 42px; border: 1px solid var(--orgmetra-border-subtle); border-radius: var(--orgmetra-radius-md); padding: 8px 10px; background: white; color: var(--orgmetra-text-primary); } +.toolbar-actions, .dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--orgmetra-space-sm); } +.button { border: 1px solid transparent; border-radius: var(--orgmetra-radius-md); padding: 9px 14px; font-weight: 700; } +.button-secondary { border-color: var(--orgmetra-border-subtle); background: white; color: var(--orgmetra-text-primary); } +.button-review { background: var(--orgmetra-action-review); color: white; } +.button-review:hover { background: #163d6e; } +.notice { display: flex; gap: var(--orgmetra-space-sm); margin: var(--orgmetra-space-md) 0; border-radius: var(--orgmetra-radius-md); padding: 12px 14px; } +.notice-danger { border: 1px solid #fecaca; background: #fef2f2; color: var(--orgmetra-danger); } +.notice-success { border: 1px solid #bbf7d0; background: #f0fdf4; color: #166534; } +.notice-neutral { border: 1px solid #cbd5e1; background: #f8fafc; color: var(--orgmetra-text-primary); } +.table-wrap { overflow-x: auto; } +table { width: 100%; border-collapse: collapse; background: white; font-size: 14px; } +th, td { border-bottom: 1px solid var(--orgmetra-border-subtle); padding: 12px; text-align: left; vertical-align: top; } +thead th { color: var(--orgmetra-text-muted); font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; } +tbody th { font-weight: 700; } +tbody tr:last-child th, tbody tr:last-child td { border-bottom: 0; } +.helper-text { margin-top: var(--orgmetra-space-md); font-size: 13px; } +.dialog { width: min(560px, calc(100% - 32px)); border: 1px solid var(--orgmetra-border-subtle); border-radius: 14px; padding: 24px; color: var(--orgmetra-text-primary); box-shadow: 0 24px 80px rgba(15, 23, 42, 0.25); } +.dialog::backdrop { background: rgba(15, 23, 42, 0.5); } +.dialog-close { border: 0; background: transparent; color: var(--orgmetra-text-muted); font-size: 26px; line-height: 1; } +.evidence-list { display: grid; gap: var(--orgmetra-space-sm); margin: 20px 0 28px; padding: 0; list-style: none; } +.evidence-list li { display: grid; grid-template-columns: 120px 1fr; gap: var(--orgmetra-space-sm); border-bottom: 1px solid var(--orgmetra-border-subtle); padding-bottom: var(--orgmetra-space-sm); } +.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--orgmetra-space-md); margin: 20px 0; } +.field-wide { grid-column: 1 / -1; } +textarea { resize: vertical; } +.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } +.storybook-preview { width: min(100%, 860px); padding: var(--orgmetra-space-lg); background: var(--orgmetra-surface-page); color: var(--orgmetra-text-primary); } +.storybook-frame { display: grid; gap: var(--orgmetra-space-lg); min-width: min(100%, 640px); } +.storybook-state-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--orgmetra-space-lg); } +.storybook-state-grid > div { display: grid; gap: var(--orgmetra-space-sm); align-content: start; } +.storybook-state-grid .eyebrow { margin-bottom: 0; } + +@media (max-width: 820px) { + .app-shell { display: block; } + .sidebar { gap: var(--orgmetra-space-sm); padding: 18px 20px; } + .nav-list { display: flex; margin-top: var(--orgmetra-space-sm); } + .nav-item { width: auto; } + .sidebar-note { display: none; } + .topbar { margin-bottom: 32px; } + .section-grid, .concept-grid { grid-template-columns: 1fr; } + .profile-toolbar { align-items: stretch; flex-direction: column; } + .toolbar-actions { justify-content: flex-start; } +} + +@media (max-width: 520px) { + .main-content { padding-inline: 16px; } + .topbar, .view-heading, .profile-heading, .panel-heading { align-items: flex-start; flex-direction: column; } + .form-grid { grid-template-columns: 1fr; } + .field-wide { grid-column: auto; } + .storybook-state-grid { grid-template-columns: 1fr; } +} diff --git a/apps/hr-workspace/workspace.stories.js b/apps/hr-workspace/workspace.stories.js new file mode 100644 index 000000000..8d813e243 --- /dev/null +++ b/apps/hr-workspace/workspace.stories.js @@ -0,0 +1,134 @@ +const actionTokens = Object.freeze({ + approve: '--orgmetra-action-approve', + review: '--orgmetra-action-review', + correct: '--orgmetra-action-correct', + 'request-evidence': '--orgmetra-action-request-evidence', + compare: '--orgmetra-action-compare', + export: '--orgmetra-action-export', + escalate: '--orgmetra-action-escalate' +}); + +const frame = (content) => `
${content}
`; + +const actionButton = ({ action, label, disabled = false, loading = false, autofocus = false }) => { + const colorToken = actionTokens[action] ?? actionTokens.review; + return ``; +}; + +const protectedReadNotConnected = ({ title, boundary }) => frame(` +
+
+
+

API-bound read

+

${title}

+
+ Not connected +
+
+ Connect the host before loading protected data. + Provide the API base URL and a short-lived authorization provider, then load the protected record. +
+

${boundary} No local fallback is used and this UI does not store the request credential.

+
+`); + +export default { + title: 'Orgmetra/HR Workspace', + tags: ['autodocs'] +}; + +export const ActionButtons = { + name: 'HrActionButton states', + render: () => frame(` +
+

Default

${actionButton({ action: 'review', label: 'Review evidence' })}
+

Focus-visible ready

${actionButton({ action: 'approve', label: 'Approve', autofocus: true })}
+

Disabled

${actionButton({ action: 'correct', label: 'Correct history', disabled: true })}
+

Loading

${actionButton({ action: 'request-evidence', label: 'Request evidence', loading: true })}
+
+ `) +}; + +export const KeyboardBypass = { + name: 'Keyboard bypass — focused', + render: () => ` +
+ +
+ +

WCAG 2.4.1 interaction state

Keyboard bypass target

The first keyboard action exposes a visible bypass control that moves focus beyond repeated navigation.

+
+
+ ` +}; + +export const FieldStates = { + name: 'Read-only and validation error', + render: () => frame(` +
+ + +
+ `) +}; + +export const PermissionDenied = { + render: () => frame(` +
+

Purpose-bound access

Permission denied

Recruiting
+ +
+ `) +}; + +export const EvidenceDrawer = { + render: () => frame(` + +

Evidence drawer

Decision packet evidence

+

Reviewable inputs remain visible before a high-impact action.

+
  • EV-2026-014Structured interview criterion ratings
  • EV-2026-021SME-approved job profile version 4
+
${actionButton({ action: 'request-evidence', label: 'Request more evidence' })}
+
+ `) +}; + +export const HighRiskConfirmation = { + render: () => frame(` + +

High-impact confirmation

Correct history

+

Preview, actor, purpose, reason, and evidence context are required before confirmation.

+
+
${actionButton({ action: 'correct', label: 'Confirm correction' })}
+
+ `) +}; + +export const AssignmentSplit = { + render: () => frame(` +
+

Assignment split

Visible allocation capacity

100.00%
+
Exact assignment allocation values
AssignmentAllocationNext action
Platform60.00%No action required
Governance40.00%No action required
+
+ `) +}; + +export const PeopleNotConnected = { + name: 'People API — not connected', + render: () => protectedReadNotConnected({ + title: 'Protected People record', + boundary: 'The host owns connection and authorization setup.' + }) +}; + +export const JobAnalysisNotConnected = { + name: 'Job Analysis API — not connected', + render: () => protectedReadNotConnected({ + title: 'Job Analysis snapshot', + boundary: 'The host owns connection and authorization setup.' + }) +}; diff --git a/docs/PRD.md b/docs/PRD.md index 674a3b96c..579ddbb52 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -59,6 +59,12 @@ Current HR systems often separate job architecture, recruiting, assessment, empl - Employee profile with bitemporal assignment history. - Validation dashboard shell. +The checkout also contains a local fixture slice at `apps/hr-workspace/` for +HR Home and Employee Profile, with a local Storybook runtime for its tokenized +states. It is an interaction and accessibility contract for the protected +People API boundary, not a connected or deployed customer workflow until its +API and browser E2E evidence are merged and released. + ### P2 scale - HRIS migration pipelines. diff --git a/docs/STORYBOOK.md b/docs/STORYBOOK.md index bd3dc7e15..61c343d73 100644 --- a/docs/STORYBOOK.md +++ b/docs/STORYBOOK.md @@ -5,6 +5,7 @@ Design tokens live in `packages/design-tokens/` and map to the Figma file at htt ## Component inventory - `HrActionButton` (tokenized approve/review/correct/request-evidence/compare/export/escalate) +- `KeyboardBypass` (focused skip-to-main state tied to Figma HR Home node `1:10`) - `Button` - `LinkButton` - `TextField` @@ -44,7 +45,41 @@ Each interactive component requires at least these stories where applicable: ## Accessibility contract +- The first keyboard focus on a role workspace exposes a visible skip-to-main control before repeated workspace navigation; activation moves focus to the `main` landmark. +- The bypass label follows the active English/Korean locale and its focus treatment consumes the shared Orgmetra focus-ring token. - All charts require exact-value tables. - Every evidence citation opens a keyboard-accessible drawer. - High-impact actions require preview, reason, actor, purpose, and confirmation. - Missing evidence is shown as `unknown`, not `failed`. + +## Local executable slice + +`apps/hr-workspace/` is the first dependency-free executable slice of the +Employee Profile and HR Home experience. It consumes the shared CSS tokens, +keeps the Figma node IDs in the markup, and exercises keyboard bypass, +evidence review, purpose-bound permission denial, high-impact confirmation, +exact allocation values, and English/Korean labels. The Job Analysis and +Employee Profile People views are API-bound read surfaces: a host may inject +an API base URL and short-lived authorization provider through +`globalThis.__ORGMETRA_JOB_ANALYSIS__` and `globalThis.__ORGMETRA_PEOPLE__`. +The fixture has no such provider and therefore makes no connected-data claim +or local-data fallback. + +## Local Storybook runtime + +The repository uses Storybook `10.5.10` with +`@storybook/web-components-vite` and native HTML/CSS stories in +`apps/hr-workspace/workspace.stories.js`. The stories cover tokenized action +states, the focused keyboard-bypass state, read-only and validation-error +fields, purpose-bound denial, the keyboard-accessible evidence drawer, +high-impact confirmation, and exact assignment values. Shared design tokens +and workspace CSS are imported by `.storybook/preview.js`. + +Run `npm run storybook` for the local development UI or +`npm run build-storybook` for the static build. This is local component and +state evidence. Run `npm run test:e2e` for the Chromium browser contract, which +proves the initial keyboard bypass, human-review, permission, locale, +host-injected read, authorization, and no-fallback error states against a local +static runtime. This still does not prove a protected deployment: the Job +Analysis and People read surfaces require a real protected API runtime before +they can be called released. diff --git a/docs/TEST_STRATEGY.md b/docs/TEST_STRATEGY.md index c20813b72..e25219a1b 100644 --- a/docs/TEST_STRATEGY.md +++ b/docs/TEST_STRATEGY.md @@ -12,6 +12,8 @@ npm run validate The command runs Python repository-integrity validation, the dependency-free Node foundation validator, Node regression tests, and mutation-style OpenAPI operation-contract tests. It must fail on a missing required artifact, manifest mismatch, invalid database name, missing tenant/evidence/audit/temporal DDL contract, incomplete high-risk OpenAPI operation context, empty OpenID Connect scope requirement, internal trace identifier in a client error schema, explicit unfinished-work marker, unbalanced Markdown fence, or incomplete Apache-2.0 license. Ordinary explanatory prose may contain words such as `placeholder`; only explicit TODO/TBD/FIXME marker forms are treated as unfinished work. +Python service tests use each service's project metadata, local `uv` source mappings, and checked lockfile. The canonical Job Analysis command is `uv run --project services/job-analysis-api --extra test pytest services/job-analysis-api/tests`; it resolves the owned HRIS kernel and Keyverse adapter from the repository and does not depend on a manually supplied `PYTHONPATH`. + ## Foundation test matrix | Evidence | Execution command | @@ -34,7 +36,7 @@ The command runs Python repository-integrity validation, the dependency-free Nod | Tenant/actor/purpose authorization matrix and negative high-impact commands | service-specific unit and integration test commands recorded in each service package | | AsyncAPI/CloudEvents envelope compatibility | provider and consumer contract test commands recorded beside the versioned event schema | | External adapter timeout, malformed response, tenant mismatch, and unavailable-state handling | fake-server tests in each adapter package | -| Role-workspace keyboard, focus, exact-value, permission-denied, and confirmation states | Storybook interaction/a11y tests plus browser E2E for the owning workspace | +| Role-workspace keyboard, focus, exact-value, permission-denied, and confirmation states | Storybook interaction/a11y tests plus `npm run test:e2e` for the owning workspace | The PostgreSQL scripts apply the checked-in migration chain required by the contract under test to a fresh database. The bitemporal and evidence-sealing tests execute concurrency regressions with an observable database barrier instead of a fixed scheduling assumption. The tenant-isolation test proves both read and write enforcement with unprivileged `NOLOGIN NOBYPASSRLS` roles, so table-owner/superuser bypass cannot manufacture a passing tenant result. The evidence-sealing test compares database output with independently precomputed canonical SHA-256 fixtures and forces a membership transaction to hold the evidence-set row lock before finalization, proving the digest snapshot includes evidence that committed first. The audit/outbox contract stores exact `AuditOutboxEvent.canonical_json()` bytes, independently verifies their SHA-256 digest in PostgreSQL, rejects extra top-level PII fields even when a caller recomputes the digest, and exercises outbox lifecycle invariants separately from immutable audit facts. The outbox-claim contract proves an already-expired lease cannot be created, verifies deterministic tenant-scoped claims return the immutable event/digest while live leases are excluded, then lets a valid one-second lease expire and requires atomic takeover of that same row with attempt count 2, a new future lease, and explicit `lease_expired` evidence. The dead-letter contract applies migrations 0001 through 0007, proves the dispatcher cannot select its own terminal attempt budget, rejects direct terminal DML before matching immutable escalation evidence and the stored budget are satisfied, exercises the real retry/claim path through the database-owned default fifth attempt, rejects retry at attempt five, lets the final lease expire, proves a replacement worker cannot create attempt six, proves the row remains bound to the recorded worker identity, rejects a foreign finalizer, permits that exact recorded identity to append terminal evidence after expiry, and rejects fabricated escalation evidence for nonterminal work. The People mutation idempotency contract applies the authoritative migration chain through 0012, verifies the replay record is written in the same transaction as its authoritative fact and audit/outbox evidence, proves rollback leaves no false replay marker, and uses concurrent exact-key sessions to prove one canonical committed identity wins without duplicate business facts. Foundation CI executes every matrix entry independently; a cancelled, skipped, queued, absent, neutral, failed, stale, predecessor-head, status-only, or model-only matrix result is not database evidence for the current head. @@ -133,3 +135,17 @@ A model that omits evidence for a structural feature it uses is not eligible for - Permission-denied and Keyverse-unavailable states. - High-risk review, confirmation, recording, and audit states. - Narrow viewport, 200% zoom/reflow, reduced-motion, and high-contrast review. + +The current HR workspace browser contract runs Chromium against the static +workspace with Playwright. It covers the Employee Profile permission boundary, +English/Korean accessible labels, required-reason focus behavior, host-injected +People and Job Analysis reads, authorization/purpose request data, and denied +read errors without fixture fallback. Run it with: + +```text +npm run test:e2e +``` + +The browser contract is executable local/CI evidence; it does not promote the +fixture to a connected production deployment or authorize an employment +decision. diff --git a/docs/TRACEABILITY.md b/docs/TRACEABILITY.md index 22a4178fe..e9cdf5dfc 100644 --- a/docs/TRACEABILITY.md +++ b/docs/TRACEABILITY.md @@ -13,9 +13,10 @@ | Effective/system time | Bitemporal HRIS | `effective_from`, `recorded_from` | strict half-open interval and historical-coordinate tests | ADR-0003 | implemented_on_active_pr | | Evidence-backed human selection decisions | Talent Acquisition | `decision_evidence_set`, `selection_decision_evidence`, `selection_decision` | database-owned SHA-256 sealing, non-empty evidence, drift/reuse rejection, OpenAPI human-confirmation tests | ADR-0001 | implemented_on_active_pr | | Governed candidate-to-worker conversion | Talent Acquisition / People core | `candidate_worker_conversion_record` with candidate, person, employment, selection decision, audit event and outbox evidence | PostgreSQL exact hire/evidence/audit-envelope binding, correction provenance, tenant RLS, legacy-write rejection and bitemporal history contract | ADR-0001, ADR-0003, ADR-0006 | implemented_on_protected_main | -| GET-only People API | People API / purpose-bound read boundary | `GET /v1/tenants/{tenant_record_id}/people/{person_record_id}`, `read_worker_people_record()`, `PostgresPeopleReadPort` | People API HTTP and PostgreSQL read contracts with exact 100% owned statement/branch coverage; current conversion lineage; no mutation writes | ADR-0002, ADR-0008 | implemented_on_protected_main | -| Governed People writes and confirmed-hire materialization | People API / purpose-bound mutation boundary | `POST /v1/employment-records`, `POST /v1/position-records`, `POST /v1/assignment-records`, `POST /v1/tenants/{tenant_record_id}/candidate-worker-conversions`, `people_mutation_idempotency_record` | People command/HTTP/PostgreSQL contracts with exact owned statement/branch coverage plus PostgreSQL tenant-RLS, atomic audit/outbox/idempotency, identical-retry replay, changed-command rejection, rollback, and concurrent-key regression | ADR-0002, ADR-0006, ADR-0008 | implemented_on_protected_main | -| Evidence-grounded Job analysis with governed Task/FJA/KSAO persistence | Job Analysis / Workforce Validation | `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `FunctionalJobAnalysisProfile`, `TaskKSAOLink`, `EvidenceSource`, `job_analysis_snapshot`, `job_analysis_task_item`, `job_analysis_ksao_item`, `job_analysis_task_ksao_link`, `job_analysis_write_command`, `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots`, `GET /v1/tenants/{tenant_record_id}/job-analysis-snapshots/{analysis_record_id}` | domain tenant/Job isolation, source/version/digest provenance, task-KSAO completeness, deterministic canonicalization, accountable human-review and LLM-draft-only regressions; migration 0013 PostgreSQL parent-scope/RLS/append-only/idempotency/audit-outbox persistence; exact route/OpenAPI/error contracts and 100% owned service statement/branch coverage | ADR-0007, ADR-0014 | implemented_on_active_pr | +| People read API | People API / purpose-bound read boundary | `GET /v1/tenants/{tenant_record_id}/people/{person_record_id}`, `read_worker_people_record()`, `PostgresPeopleReadPort` | People API HTTP and PostgreSQL read contracts with exact 100% owned statement/branch coverage; current conversion lineage; no protected-value read after denied authorization | ADR-0002, ADR-0008 | implemented_on_protected_develop | +| Governed People writes and confirmed-hire materialization | People API / purpose-bound mutation boundary | `POST /v1/employment-records`, `POST /v1/position-records`, `POST /v1/assignment-records`, `POST /v1/tenants/{tenant_record_id}/candidate-worker-conversions`, `people_mutation_idempotency_record` | People command/HTTP/PostgreSQL contracts with exact owned statement/branch coverage plus PostgreSQL tenant-RLS, atomic audit/outbox/idempotency, identical-retry replay, changed-command rejection, rollback, and concurrent-key regression | ADR-0002, ADR-0006, ADR-0008 | implemented_on_protected_develop | +| HR Home and Employee Profile fixture, Storybook state runtime, and browser contract | Product / web workspace | `apps/hr-workspace/index.html`, `apps/hr-workspace/app.js`, `apps/hr-workspace/workspace.stories.js`, `.storybook/`, `playwright.config.mjs`, `tests/e2e/hr-workspace.spec.mjs`, shared design tokens, Figma nodes `1:10` and `1:28` | `npm run validate`, `npm run build-storybook`, `npm run test:e2e`; local Chromium proves fixture/API, permission, confirmation, exact-value, focus, locale, host-authorization, and no-fallback states; protected deployment remains open | ADR-0015, `docs/STORYBOOK.md` | implemented_on_active_pr | +| Evidence-grounded Job analysis with Task/FJA/KSAO linkage | Job Analysis / Workforce Validation | `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `FunctionalJobAnalysisProfile`, `TaskKSAOLink`, `EvidenceSource` | tenant/Job isolation, source/version/digest provenance, task-KSAO completeness, deterministic canonicalization, human-review and LLM-draft-only regressions with exact 100% owned statement/branch coverage | ADR-0007 | implemented_on_protected_develop | | Job-, cycle-, and staffing-scoped performance criterion observations | Performance / Workforce Validation | `criterion_observation`, `criterion_blueprint`, `performance_cycle`, `assignment_record`, `employment_record_version`, `position_record`, `position_record_version` | PostgreSQL wrong-Job, pre-assignment, out-of-cycle, frozen-Position, terminated-employment, closed-recorded-time, and session-TimeZone/UTC-midnight rejection plus valid worker-Job/staffing acceptance | ADR-0009 | implemented_on_protected_main | | Governed immutable audit and transactional outbox persistence | Audit Provenance / Integration Hub | `AuditOutboxEvent.canonical_json()`, `audit_event_record`, `outbox_delivery_record`, SHA-256 envelope digest | canonical-byte/digest regression plus PostgreSQL digest, allowlist/PII, high-impact confirmation, append-only, atomicity, lease-transition, terminal-state, and reserved-UUID tests | ADR-0006 | implemented_on_active_pr | | Tenant-safe atomic outbox claiming and crash recovery | Integration Hub dispatcher boundary | `outbox_delivery_record` pending/expired-lease claim indexes plus `claim_outbox_delivery(...)` | PostgreSQL already-expired-new-lease rejection, due-order claim, live-lease exclusion, pre-exhaustion takeover with `lease_expired` evidence, retry-budget claim bound, tenant-context binding, opaque-worker validation, and bounded-lease contract | ADR-0006 | implemented_on_active_pr | @@ -24,7 +25,8 @@ | Purpose-bound PII access | Security architecture / Keyverse adapter boundary | `PurposeBoundAccessPolicy`, `PurposeBoundAccessRequest.resource_reference`, `AuthorizationDecision.resource_reference` | exact tenant/actor/resource binding, exact opaque target correlation for allow/deny audit evidence, resource/purpose/operation matching, operation-specific scope, field-subset minimization, malformed-attribute rejection, reserved-UUID rejection, PII-minimized denial evidence, and exact 100% owned statement/branch coverage | ADR-0008 | implemented_on_protected_main | | Least-privilege API capability | Keyverse gateway boundary | operation scope conceptual | structural per-operation scope and confused-deputy contract tests | ADR-0002 | implemented_on_active_pr | | Client-safe failure correlation | API error boundary | `support_reference` conceptual | error disclosure and support-lookup tests | ADR-0002 | implemented_on_active_pr | -| Foundation artifact integrity | Repository governance | deterministic `manifest.json` file inventory | SHA-256/byte/line validation plus Python/Node inventory-equivalence regression and explicit dispatcher/validity/criterion/job-analysis migration and execution-contract provenance regression | ADR-0001 | implemented_on_active_pr | +| Foundation artifact integrity | Repository governance | deterministic `manifest.json` file inventory | SHA-256/byte/line validation plus Python/Node inventory-equivalence regression and explicit dispatcher/validity/criterion migration and execution-contract provenance regression | ADR-0001 | implemented_on_active_pr | +| Product and technical gap baseline | Product / platform governance | `docs/product-technical-gap-baseline.md`, maturity vocabulary, current protected head and PR inventory | Fresh local contract/coverage evidence plus current GitHub head/review/check inventory | ADR-0015 | implemented_on_protected_develop | ## 4. CWL integration traceability diff --git a/docs/WIREFRAMES.md b/docs/WIREFRAMES.md index 15d4f4e9a..e4855d170 100644 --- a/docs/WIREFRAMES.md +++ b/docs/WIREFRAMES.md @@ -11,6 +11,8 @@ The Figma baseline contains six role-based wireframes: Figma file: https://www.figma.com/design/xu1ZK1zmtFcDep95R8oE9O +The Figma baseline was re-verified against the live `Orgmetra Baseline` page for this interaction slice. Figma nodes `1:10` (HR Home) and `1:28` (Employee Profile) remain the visual geometry baseline. The keyboard bypass control below is intentionally a focus-only interaction affordance rather than a persistent geometric change to those frames; its visible focus state is captured in Storybook and its behavior is enforced by browser tests. + ## HR Home Primary action cards: @@ -20,6 +22,12 @@ Primary action cards: - Resolve effective-date conflict - Open validation study +Keyboard interaction contract: + +- The first keyboard-focusable control is **Skip to main content** / **본문으로 건너뛰기**. +- It becomes visibly rendered when focused and moves focus to the `main` landmark, bypassing repeated workspace navigation. +- The control follows the active English/Korean workspace locale and uses the shared focus-ring token. + ## Job Architecture Panels: @@ -53,6 +61,8 @@ Panels: - Manager and organization timeline - Performance criteria and observations +The same page-level keyboard bypass contract applies before the Employee Profile navigation path, so repeated sidebar navigation is not a prerequisite to reaching the profile content. + ## Validate Panels: diff --git a/docs/adr/0006-governed-audit-outbox-envelope.md b/docs/adr/0006-governed-audit-outbox-envelope.md index bd86f2684..c490e9b33 100644 --- a/docs/adr/0006-governed-audit-outbox-envelope.md +++ b/docs/adr/0006-governed-audit-outbox-envelope.md @@ -1,6 +1,7 @@ # ADR-0006: Governed audit/outbox envelope and durable persistence -- **Status:** Accepted for the stacked implementation branch; not protected-main truth until merged. +- Status: Accepted +- Provenance: integrated on `develop`; enforceable branch protection is tracked by Orgmetra issue #89. - **Decision date:** 2026-08-17 - **Scope:** Orgmetra-owned audit envelope, immutable audit persistence, guarded outbox delivery state, tenant-safe atomic dispatcher claiming, expired-lease takeover, owner-bound completion/retry, database-budget-governed terminal dead-letter escalation, review hardening, and privileged recovery of an expired exhausted lease when its recorded final worker identity is permanently unavailable. Exponential retry policy, retention/export workflows, and external delivery receipts remain subsequent work. @@ -59,7 +60,7 @@ The branch contains test-first application and PostgreSQL regressions for determ Review hardening added a focused PostgreSQL RED contract before migration 0008. That contract requires statement-level audit/outbox TRUNCATE denial, trusted search paths on every audited dispatcher/recovery boundary, deterministic/session-independent immutable envelope validation, the due-work partial index, and operator terminalization of only an expired exhausted lease with immutable operator-attributed escalation evidence. The operator regression executes recovery through the externally assignable NOLOGIN capability role, proves both service-owned recovery roles are non-superuser and NOBYPASSRLS, proves neither participates in a pre-existing membership edge, proves the temporary schema CREATE grant is absent after migration, and proves the operator role cannot read/update outbox state or insert escalation evidence directly. A dedicated preflight regression creates a colliding reserved role name and requires migration 0008 to fail before creating its due-work index or recovery function, then removes the collision and runs the normal migration. Additional review regressions make every captured dispatcher/dead-letter `psql` assertion fail on SQL errors, execute audit persistence sessions with explicit tenant context, assert the exact duplicate-delivery primary-key failure for transaction rollback, prove non-UTC application timestamps normalize to UTC, discover all executable migration/PostgreSQL-contract artifacts for provenance, and validate the database contract across all migrations rather than a hardcoded prefix. -Exact-current-head hosted evidence is required after every branch mutation. Queued, cancelled, stale, predecessor, or model-only results are non-passing and do not change this ADR’s protected-main status. +Exact-current-head hosted evidence is required after every branch mutation. Queued, cancelled, stale, predecessor, or model-only results are non-passing and do not confer merge authorization while the repository protection defect tracked by issue #89 remains unresolved. ## References diff --git a/docs/adr/0007-governed-job-analysis-evidence.md b/docs/adr/0007-governed-job-analysis-evidence.md index f9aeea835..cb15b5acd 100644 --- a/docs/adr/0007-governed-job-analysis-evidence.md +++ b/docs/adr/0007-governed-job-analysis-evidence.md @@ -1,6 +1,6 @@ # ADR 0007: Governed job-analysis evidence snapshots -- Status: Accepted on stacked implementation branch +- Status: Accepted - Date: 2026-08-17 - Owners: Orgmetra Job Analysis / Workforce Validation @@ -44,7 +44,7 @@ This contract does not make hiring, promotion, termination, compensation, or oth ### Costs and limitations -- Persistence of the canonical snapshot as tenant-scoped 3NF rows is specified by ADR 0014. SME workflow, source ingestion, retention/export controls, UI, and selection-validity computation remain separate owner boundaries. +- This slice is a pure domain/evidence contract; persistence, SME workflow, source ingestion, authorization, retention/export controls, UI, and selection-validity computation remain separate owner boundaries. - The 1–5 rating scales are contract-level normalized ordinals. A production job-analysis method must document its sampling, anchors, aggregation, criticality rules, inter-rater treatment, and local validation rationale rather than infer those properties from the ordinal values alone. - O*NET provides occupation-level evidence and does not eliminate the need to verify local Job content, context, and essential requirements with appropriate job experts. diff --git a/docs/adr/0010-naruon-calendar-intent-boundary.md b/docs/adr/0010-naruon-calendar-intent-boundary.md index 6bed4dd49..405b833f5 100644 --- a/docs/adr/0010-naruon-calendar-intent-boundary.md +++ b/docs/adr/0010-naruon-calendar-intent-boundary.md @@ -2,7 +2,9 @@ ## Status -Accepted on active PR only. This document is not protected-`develop` product truth until its owning PR integrates. +Status: Accepted + +Provenance: integrated on `develop`; enforceable branch protection is tracked by Orgmetra issue #89. ## Context diff --git a/docs/adr/0011-bitemporal-workforce-composition.md b/docs/adr/0011-bitemporal-workforce-composition.md index 7e9302870..9986e603d 100644 --- a/docs/adr/0011-bitemporal-workforce-composition.md +++ b/docs/adr/0011-bitemporal-workforce-composition.md @@ -2,7 +2,9 @@ ## Status -Accepted on active PR #33 only. This document is not protected-`develop` product truth until the owning PR integrates. +Status: Accepted + +Provenance: integrated on `develop`; enforceable branch protection is tracked by Orgmetra issue #89. ## Context diff --git a/docs/adr/0012-governed-migration-handoff.md b/docs/adr/0012-governed-migration-handoff.md index ec9ab40f0..c90e58ad0 100644 --- a/docs/adr/0012-governed-migration-handoff.md +++ b/docs/adr/0012-governed-migration-handoff.md @@ -2,7 +2,9 @@ ## Status -Accepted on this active PR only. This is not protected-`develop` product truth until the owning PR integrates. +Status: Accepted + +Provenance: integrated on `develop`; enforceable branch protection is tracked by Orgmetra issue #89. ## Context diff --git a/docs/adr/0014-job-analysis-snapshot-persistence.md b/docs/adr/0014-job-analysis-snapshot-persistence.md index cef05e28f..6d9125812 100644 --- a/docs/adr/0014-job-analysis-snapshot-persistence.md +++ b/docs/adr/0014-job-analysis-snapshot-persistence.md @@ -1,6 +1,6 @@ # ADR 0014: Persist governed job-analysis snapshots -- Status: Accepted on active implementation branch +- Status: Accepted - Date: 2026-08-20 - Owners: Orgmetra Job Analysis / Workforce Validation diff --git a/docs/adr/0017-governed-offer-approval.md b/docs/adr/0017-governed-offer-approval.md index c662a0429..ebc4f073b 100644 --- a/docs/adr/0017-governed-offer-approval.md +++ b/docs/adr/0017-governed-offer-approval.md @@ -1,12 +1,12 @@ # ADR 0017: Governed offer approval evidence -- Status: Proposed — active PR only +- Status: Accepted on protected develop - Date: 2026-08-19 - Scope: Talent Acquisition offer review ## Context -Protected `develop` can govern candidate, requisition, selection, and employment evidence, but it does not yet expose a bounded pre-send contract proving that a proposed offer is tied to the selected candidate, authoritative Job/optional Position, reviewed selection decision, compensation-package provenance, offer-terms provenance, and accountable human approval. +Protected `develop` can govern candidate, requisition, selection, and employment evidence and now contains the bounded pre-send offer-approval contract proving that a proposed offer is tied to the selected candidate, authoritative Job/optional Position, reviewed selection decision, compensation-package provenance, offer-terms provenance, and accountable human approval. Offer review is high-impact employment workflow. A governance envelope must not become an alternate decision authority, a salary-value cache, or a channel that lets generated/model material masquerade as an approved offer. Different opaque requester/approver references also do not prove that the authoritative actor boundary resolves them to different people, and UUID syntax does not prove that the referenced candidate, requisition, Job/Position, selection decision, compensation package, or offer terms belong to the packet tenant. Packet-owned UUIDv1 references also carry timestamp/node-derived correlation metadata. The authoritative tenant identifier is different: it is issued by Orgmetra core, so this leaf package must accept the canonical non-sentinel operational UUID contract owned by that boundary rather than silently imposing a second version policy. @@ -30,7 +30,7 @@ Canonical JSON and SHA-256 are audit-correlation evidence only. The packet does A buyer can review one deterministic, PII-minimized envelope before an offer moves to the authoritative offer workflow. Compensation values stay in their purpose-bound owner boundary, while Orgmetra keeps exact provenance references, evidence version, and human accountability. Packet-owned UUIDv1/non-v4 references fail closed before serialization without making this leaf package incompatible with authoritative Orgmetra tenant UUIDs. Cross-tenant evidence mixing is fail-closed at the host approval boundary because every packet reference must resolve in the exact tenant. Requester/approver separation is proven only after tenant-scoped authoritative actor resolution. New offer-review reason categories require an explicit contract change and regression evidence rather than accepting arbitrary caller text. -Downstream offer persistence/execution must independently enforce authorization, tenant-scoped source-evidence resolution, idempotency where applicable, and immutable audit/outbox evidence. This ADR remains proposed active-PR truth until integrated into protected `develop`. +Downstream offer persistence/execution must independently enforce authorization, tenant-scoped source-evidence resolution, idempotency where applicable, and immutable audit/outbox evidence. The packet contract is protected `develop` truth; connected buyer workflow and release evidence remain separate work. ## References diff --git a/docs/adr/0025-governed-candidate-evidence-intake.md b/docs/adr/0025-governed-candidate-evidence-intake.md index ab66b3088..dd4516768 100644 --- a/docs/adr/0025-governed-candidate-evidence-intake.md +++ b/docs/adr/0025-governed-candidate-evidence-intake.md @@ -1,6 +1,7 @@ # ADR 0025: Govern candidate evidence intake as reference-only evidence -- **Status:** Proposed — active PR only +- Status: Accepted +- Provenance: integrated on `develop`; enforceable branch protection is tracked by Orgmetra issue #89. - **Date:** 2026-08-19 ## Context @@ -40,7 +41,7 @@ Canonical JSON plus SHA-256 provide immutable audit correlation but do not estab - The packet does not store raw candidate evidence, decide whether an item is lawfully usable, or prove the referenced policy was followed. - UUID-backed tenant and candidate references are still sensitive correlating metadata and require least-privilege handling. - Evidence sealing, authoritative selection decisions, immutable audit/outbox, deletion/retention execution, export controls, accommodations, adverse-impact monitoring, and jurisdiction-specific legal review remain separate obligations. -- This ADR remains proposed until its exact PR head merges into protected `develop`. +- This ADR is integrated on `develop`; repository-level merge authorization still depends on the independent-review and branch-protection controls tracked by issue #89. ## References diff --git a/docs/adr/0026-product-technical-gap-baseline.md b/docs/adr/0026-product-technical-gap-baseline.md new file mode 100644 index 000000000..fea907dc3 --- /dev/null +++ b/docs/adr/0026-product-technical-gap-baseline.md @@ -0,0 +1,32 @@ +# ADR 0026: Product and technical gap baseline + +- Status: Accepted +- Date: 2026-08-20 +- Owners: Orgmetra Product / Platform + +## Context + +Orgmetra has a strong evidence and integrity foundation, but its documentation has repeatedly mixed protected `develop` truth, active pull requests, accepted architecture, and planned product work. A buyer must be able to tell which workflow can be executed today, which is review-ready but unmerged, and which is only a design promise. + +The product baseline also uses a Figma wireframe source and repeated HR actions. The source file key is `xu1ZK1zmtFcDep95R8oE9O`; it is recorded here so design-to-code work can be traced to one design source. The implementation must continue to use `packages/design-tokens/` rather than inventing one-off action colors. + +## Decision + +1. `docs/product-technical-gap-baseline.md` is the current evidence ledger for buyer-visible product gaps and technical gaps. +2. Every capability in the ledger has one maturity value: `implemented_on_protected_develop`, `implemented_on_active_pr`, `accepted_architecture`, `planned`, `research_only`, `superseded`, or `out_of_scope`. +3. Protected-default-branch claims require current `develop` evidence. An OpenAPI definition, a passing predecessor workflow, a local branch, or a PR body cannot be presented as shipped runtime behavior. +4. The authoritative People mutation and confirmed-hire paths are protected integration truth. Browser workflows must preserve tenant authorization, idempotency, bitemporal history, human confirmation, audit, and outbox atomicity rather than bypassing those boundaries. +5. Job-analysis persistence/API is protected `develop` truth through merged PR #38, migration 0013, ADR-0014, and the governed Job Analysis API. Extensions must reuse that canonical Task/FJA/KSAO model instead of introducing a second store. +6. Statistical validity computation remains a separate scientific boundary. Integrity linkage is necessary evidence hygiene, not a validity result. Any future numerical kernel is Rust-first and must publish CPU reference, multilevel/multiple-membership, temporal, uncertainty, convergence, and GPU-parity evidence where GPU execution is material. +7. Figma remains a design-system input, while the local Storybook runtime is executable component/state evidence rather than evidence of a connected customer UI. A release claim requires executable UI, keyboard/accessibility checks, interaction tests, and browser evidence for the owning workflow. + +## Consequences + +- Product and engineering planning use the same gap IDs and acceptance evidence. +- Review, merge, release, and scheduled-loop automation can consume one small status contract instead of inferring maturity from filenames or PR titles. +- Figma remains traceable without copying a design file into the repository. +- A gap can be closed only when the required runtime, documentation, tests, and protected-branch evidence all exist. + +## References + +See `docs/doctoring/REFERENCES.md` for APA 7 sources, including ISO 30405:2023, NIST AI RMF 1.0, AICPA Trust Services Criteria, WCAG 2.2, Fugu, Conductor, and TRINITY. diff --git a/docs/adr/README.md b/docs/adr/README.md index 099a21139..d474110e1 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -1,18 +1,23 @@ # ADR Index -| ADR | Title | Status | -|---|---|---| -| [0001](0001-orgmetra-authoritative-hris-record.md) | Orgmetra owns authoritative HRIS records | Accepted | -| [0002](0002-federated-cwl-integration-boundaries.md) | Federated CWL integration boundaries | Accepted | -| [0003](0003-bitemporal-hris-data-contract.md) | Bitemporal HRIS data contract | Accepted | -| [0004](0004-employment-position-version-and-assignment-binding.md) | Employment and position versions bind assignments | Accepted | -| [0005](0005-exclusive-employment-and-staffable-seats.md) | Exclusive employment and staffable seats | Accepted | -| [0006](0006-governed-audit-outbox-envelope.md) | Governed audit/outbox envelope and durable persistence | Accepted on stacked implementation branch | -| [0007](0007-governed-job-analysis-evidence.md) | Governed job-analysis evidence snapshots | Accepted on stacked implementation branch | -| [0008](0008-purpose-bound-pii-authorization.md) | Purpose-bound PII authorization | Accepted on protected `develop` | -| [0009](0009-performance-criterion-observation-scope.md) | Performance criterion observations require worker-job scope | Accepted on active implementation branch | -| [0010](0010-naruon-calendar-intent-boundary.md) | Naruon calendar intent boundary | Accepted on active implementation branch | -| [0011](0011-bitemporal-workforce-composition.md) | Bitemporal workforce composition | Accepted on active implementation branch | -| [0012](0012-governed-migration-handoff.md) | Governed migration handoff | Accepted on active implementation branch | -| [0013](0013-governed-requisition-review-packet.md) | Governed requisition review packet | Accepted on active implementation branch | -| [0014](0014-job-analysis-snapshot-persistence.md) | Persist governed job-analysis snapshots | Accepted on active implementation branch | +`Status` is the canonical ADR decision state validated against each ADR file. `Provenance` records where that state is evidenced and must not be folded into the status cell, because doing so would bypass the index-to-file status check. `develop` entries below are integrated repository truth, but enforceable branch protection is currently tracked separately by issue #89 and therefore is not claimed here. + +| ADR | Title | Provenance | Status | +|---|---|---|---| +| [0001](0001-orgmetra-authoritative-hris-record.md) | Orgmetra owns authoritative HRIS records | — | Accepted | +| [0002](0002-federated-cwl-integration-boundaries.md) | Federated CWL integration boundaries | — | Accepted | +| [0003](0003-bitemporal-hris-data-contract.md) | Bitemporal HRIS data contract | — | Accepted | +| [0004](0004-employment-position-version-and-assignment-binding.md) | Employment and position versions bind assignments | — | Accepted | +| [0005](0005-exclusive-employment-and-staffable-seats.md) | Exclusive employment and staffable seats | — | Accepted | +| [0006](0006-governed-audit-outbox-envelope.md) | Governed audit/outbox envelope and durable persistence | `develop`; protection gap #89 | Accepted | +| [0007](0007-governed-job-analysis-evidence.md) | Governed job-analysis evidence snapshots | `develop`; protection gap #89 | Accepted | +| [0008](0008-purpose-bound-pii-authorization.md) | Purpose-bound PII authorization | `develop`; protection gap #89 | Accepted | +| [0009](0009-performance-criterion-observation-scope.md) | Performance criterion observations require worker-job scope | `develop`; protection gap #89 | Accepted | +| [0010](0010-naruon-calendar-intent-boundary.md) | Naruon calendar intent boundary | `develop`; protection gap #89 | Accepted | +| [0011](0011-bitemporal-workforce-composition.md) | Bitemporal workforce composition | `develop`; protection gap #89 | Accepted | +| [0012](0012-governed-migration-handoff.md) | Governed migration handoff | `develop`; protection gap #89 | Accepted | +| [0013](0013-governed-requisition-review-packet.md) | Governed requisition review packet | `develop`; protection gap #89 | Accepted | +| [0014](0014-job-analysis-snapshot-persistence.md) | Persist governed job-analysis snapshots | `develop`; protection gap #89 | Accepted | +| [0017](0017-governed-offer-approval.md) | Governed offer approval evidence | `develop`; protection gap #89 | Accepted | +| [0025](0025-governed-candidate-evidence-intake.md) | Govern candidate evidence intake as reference-only evidence | `develop`; protection gap #89 | Accepted | +| [0026](0026-product-technical-gap-baseline.md) | Product and technical gap baseline | active PR #53 | Accepted | diff --git a/docs/doctoring/REFERENCES.md b/docs/doctoring/REFERENCES.md index 309409cc2..9208acf3d 100644 --- a/docs/doctoring/REFERENCES.md +++ b/docs/doctoring/REFERENCES.md @@ -12,17 +12,17 @@ Cloud Native Computing Foundation. (2022). *CloudEvents specification v1.0.2*. h Diez-Roux, A. V. (1998). Bringing context back into epidemiology: Variables and fallacies in multilevel analysis. *American Journal of Public Health, 88*(2), 216–222. https://doi.org/10.2105/AJPH.88.2.216 -Equal Employment Opportunity Commission. (1978). *Uniform guidelines on employee selection procedures*. 29 C.F.R. Part 1607. https://www.govinfo.gov/content/pkg/CFR-2025-title29-vol4/pdf/CFR-2025-title29-vol4-part1607.pdf +Equal Employment Opportunity Commission. (1978). *Uniform guidelines on employee selection procedures*. 29 C.F.R. Part 1607. Hu, V. C., Ferraiolo, D. F., & Kuhn, D. R. (2019). *Attribute considerations for access control systems* (NIST Special Publication 800-205). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-205 Hu, V. C., Ferraiolo, D. F., Kuhn, D. R., Schnitzer, A., Sandlin, K., Miller, R., & Scarfone, K. A. (2019). *Guide to attribute based access control (ABAC) definition and considerations* (NIST Special Publication 800-162). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-162 -International Organization for Standardization. (2022). *ISO 30400:2022 Human resource management — Vocabulary*. ISO. https://www.iso.org/standard/78044.html +International Organization for Standardization. (2022). *ISO 30400:2022 Human resource management — Vocabulary*. ISO. -International Organization for Standardization. (2023). *ISO 30405:2023 Human resource management — Guidelines on recruitment*. ISO. https://www.iso.org/standard/79488.html +International Organization for Standardization. (2023). *ISO 30405:2023 Human resource management — Guidelines on recruitment*. ISO. -International Organization for Standardization. (2025). *ISO 30414:2025 Human resource management — Requirements and recommendations for human capital reporting and disclosure*. ISO. https://www.iso.org/standard/30414 +International Organization for Standardization. (2025). *ISO 30414:2025 Human resource management — Requirements and recommendations for human capital reporting and disclosure*. ISO. Internet Engineering Task Force. (2024). *Universally Unique IDentifiers (UUIDs)* (RFC 9562). https://www.rfc-editor.org/rfc/rfc9562.html @@ -56,9 +56,9 @@ PostgreSQL Global Development Group. (n.d.). *SELECT (PostgreSQL 16 documentatio Robinson, W. S. (1950). Ecological correlations and the behavior of individuals. *American Sociological Review, 15*(3), 351–357. https://doi.org/10.2307/2087176 -Snodgrass, R. T. (1999). *Developing time-oriented database applications in SQL*. Morgan Kaufmann. https://lccn.loc.gov/99014298 +Snodgrass, R. T. (1999). *Developing time-oriented database applications in SQL*. Morgan Kaufmann. -Society for Industrial and Organizational Psychology. (2018). *Principles for the validation and use of personnel selection procedures* (5th ed.). SIOP. https://doi.org/10.1017/iop.2018.195 +Society for Industrial and Organizational Psychology. (2018). *Principles for the validation and use of personnel selection procedures* (5th ed.). SIOP. U.S. Department of Labor, Office of Administrative Law Judges. (1991). *Dictionary of Occupational Titles (4th ed., rev. 1991), Appendix B: Explanation of Data, People, and Things*. https://www.dol.gov/agencies/oalj/PUBLIC/DOT/REFERENCES/DOTAPPB @@ -67,3 +67,19 @@ U.S. Office of Personnel Management. (n.d.). *Job analysis*. Retrieved August 17 World Wide Web Consortium. (2013). *PROV-O: The PROV ontology*. https://www.w3.org/TR/prov-o/ World Wide Web Consortium. (2023, October 5). *Web Content Accessibility Guidelines (WCAG) 2.2*. https://www.w3.org/TR/WCAG22/ + +## Product and technical gap baseline sources + +American Institute of Certified Public Accountants. (2023). *2017 trust services criteria (with revised points of focus—2022).* https://www.aicpa-cima.com/resources/download/2017-trust-services-criteria-with-revised-points-of-focus-2022 + +Fugu Team, Sakana AI. (2026). *Sakana Fugu technical report* (arXiv:2606.21228). arXiv. https://arxiv.org/abs/2606.21228 + +International Organization for Standardization. (2023). *ISO 30405:2023: Human resource management—Guidelines on recruitment* (2nd ed.). https://www.iso.org/standard/79488.html + +National Institute of Standards and Technology. (2023). *Artificial intelligence risk management framework (AI RMF 1.0)* (NIST AI 100-1). U.S. Department of Commerce. https://doi.org/10.6028/NIST.AI.100-1 + +Nielsen, S., Cetin, E., Schwendeman, P., Sun, Q., Xu, J., & Tang, Y. (2025). *Learning to orchestrate agents in natural language with the Conductor* (arXiv:2512.04388). arXiv. https://arxiv.org/abs/2512.04388 + +Sakana AI. (2026). *TRINITY: An evolved LLM coordinator* (arXiv:2512.04695). arXiv. https://arxiv.org/abs/2512.04695 + +World Wide Web Consortium. (2024, December 12). *Web Content Accessibility Guidelines (WCAG) 2.2*. https://www.w3.org/TR/2024/REC-WCAG22-20241212/ diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md new file mode 100644 index 000000000..04c16d8da --- /dev/null +++ b/docs/product-technical-gap-baseline.md @@ -0,0 +1,162 @@ +# Orgmetra product and technical gap baseline + +**Snapshot:** 2026-08-21, Asia/Seoul +**Evidence base:** protected `develop` at `9e3e4847510e1e612b48474ba42b177b8ed824df`; current workspace PR #53 at `c45a8a53125a6075f5edb4a33e02661df4c5d1b5` immediately before this documentation snapshot commit; current GitHub PR metadata and exact-head workflow state observed on 2026-08-21. + +This document is the buyer-facing work queue. It separates what a customer can use from what exists only in an active PR or architecture document. It is updated when a protected merge, exact-head check, review, release, or runtime test changes the evidence boundary. + +## Maturity vocabulary + +| Value | Meaning | +|---|---| +| `implemented_on_protected_develop` | Executable behavior and its required evidence are on the protected default branch. | +| `implemented_on_active_pr` | Code or tests exist on a current PR, but protected-branch runtime truth is not established. | +| `accepted_architecture` | An owned boundary and contract are accepted, but the buyer workflow is not executable here. | +| `planned` | Product work is named and ordered, but implementation evidence is missing. | +| `research_only` | A paper, prototype, or external product informs a decision; it is not an Orgmetra capability. | +| `superseded` | The artifact must not be revived because a newer owner or contract replaced it. | +| `out_of_scope` | The capability belongs to another product or is intentionally not an Orgmetra decision. | + +## Executive finding + +Orgmetra is an evidence-centered HRIS foundation with protected Job Analysis, candidate-evidence, People mutation, and confirmed-hire boundaries, not yet a complete commercial HCM product. The protected branch provides durable PostgreSQL integrity contracts, a Python HRIS decision kernel, purpose-bound authorization, governed candidate-to-worker lineage, and executable Job Analysis and People read/write boundaries. The largest buyer-visible gap remains the missing connected browser product surface: the current checkout has an active-PR HR Home/Employee Profile fixture plus an API-bound Job Analysis read surface and local Storybook state runtime, but protected truth has no connected or released workspace. + +The next highest-leverage gaps are a connected/released buyer path over the now-protected Job Analysis API and actual statistical validity estimation. Existing contracts are useful foundations, but they do not substitute for a running customer path or a released deployment. + +```mermaid +flowchart LR + evidence[Job and candidate evidence] --> selection[Human selection record] + selection --> mutation[People mutation boundary] + mutation --> worker[Employment, position, assignment] + worker --> outcome[Performance outcomes] + outcome --> validity[Validity estimation] + validity --> policy[Human-reviewed policy change] + worker -. browser workspace missing .-> gap1[Gap P0-1] + worker -. buyer-connected Job Analysis path missing .-> gap2[Gap P0-2] + validity -. integrity only, no estimator .-> gap3[Gap P0-3] +``` + +## Capability truth on protected `develop` + +| Capability | Current evidence | Maturity | Buyer consequence | +|---|---|---|---| +| Person, employment, organization, job, position, assignment separation | `database/migrations/0001_foundation_schema.sql`; HRIS kernel tests; bitemporal and tenant contracts | `implemented_on_protected_develop` | Employment truth can be modeled without collapsing stable identities or historical versions. | +| Tenant isolation, append-only history, evidence sealing, audit/outbox integrity | Migrations `0001`–`0012`; PostgreSQL contract suite; `npm run validate` | `implemented_on_protected_develop` | The foundation can reject cross-tenant, temporal, evidence-drift, and unsafe delivery-state writes. | +| Candidate evidence intake | Protected candidate-evidence package, ADR `0025`, reference-only packet tests, and `Candidate Evidence Quality` workflow | `implemented_on_protected_develop` | Candidate evidence can be correlated without copying raw values or PII into the governance envelope; authoritative reference resolution and selection remain separate boundaries. | +| Candidate-to-worker conversion | Migration `0009`; `test_candidate_worker_conversion_postgres.sh`; protected traceability; People API hire route | `implemented_on_protected_develop` | Confirmed-hire materialization has a governed HTTP/service boundary; deployment and browser evidence remain separate release work. | +| People read | `services/people-api` GET route, PostgreSQL read adapter, HTTP tests | `implemented_on_protected_develop` | Authorized HR users can read a worker view; responses are no-store and field-scoped. | +| People mutations | Migration `0012`; `services/people-api` hire and mutation routes; current protected service tests and PostgreSQL contract | `implemented_on_protected_develop` | Authoritative person, employment, position, assignment, and confirmed-hire writes have a governed code boundary; hosted/browser release evidence remains open. | +| Offer approval packet | Protected `packages/offer-approval` packet, actor-separation/evidence-version tests, and `Offer Approval Quality` workflow | `implemented_on_protected_develop` | Offer approval evidence is bounded and human-reviewed; a connected buyer workflow and released deployment remain open. | +| Job-analysis value objects | `orgmetra_hris_kernel.job_analysis`; exact unit coverage | `implemented_on_protected_develop` | Evidence can be validated in a protected package and reused by the persisted Job Analysis boundary; buyer workflow connectivity remains open. | +| Job-analysis persistence/API | Protected migration `0013`, `services/job-analysis-api`, ADR `0014`, PostgreSQL contract, and exact snapshot tests on `develop` | `implemented_on_protected_develop` | A buyer-facing deployment and browser workflow are still absent, but one canonical persisted Job Analysis case/API now exists in protected code. | +| Performance criterion scope and validity-study case integrity | Migration `0010`/`0011`; PostgreSQL contracts | `implemented_on_protected_develop` | Invalid worker-Job/time links are rejected, but no statistical validity estimate is produced. | +| Statistical validity estimation | Traceability explicitly says estimation is subsequent; no Rust workspace or estimator exists in this repository | `planned` | Customers cannot measure prediction, bias, RMSE/MAE, uncertainty, convergence, temporal effects, or multiple membership. | +| Workforce composition change evidence | Active PR #54 adds same-cutoff bitemporal composition-change evidence | `implemented_on_active_pr` | Buyers can review a proposed workforce change only after the exact PR earns checks and independent approval; it is not protected truth yet. | +| Organization hierarchy snapshot evidence | Active PR #56 adds bitemporal organization hierarchy snapshot evidence | `implemented_on_active_pr` | Organizational reporting remains an active integration lane, not a protected or released buyer workflow. | +| Selection-validity analysis handoff | Active PR #57 adds the governed handoff boundary for later validity estimation | `implemented_on_active_pr` | The handoff is not a statistical estimator and does not yet produce validity, bias, RMSE, coverage, or convergence evidence. | +| Role workspaces, Storybook runtime, and browser contract | Active PR #53 has the HR Home/Employee Profile fixture, host-injected People and Job Analysis API-bound read views, Storybook `10.5.10`, and a Chromium Playwright browser contract; protected `develop` still has no customer UI | `implemented_on_active_pr` | The component/state runtime, browser states, and host-injected API boundaries are reviewable, but there is no connected or released buyer workflow in protected truth. | +| Naruon calendar adapter | `packages/naruon-adapter` package tests; traceability says planned integration | `accepted_architecture` | Calendar intent is contract-tested, not an integrated customer scheduling workflow. | +| TEPP adapter | PR #52 is a non-executing request boundary; no transport contract is established | `implemented_on_active_pr` | Temporal analysis can be prepared as governed evidence but is not executed by Orgmetra. | +| Contextual Orchestrator/OpenCode model path | Named in architecture; no Orgmetra adapter or evidence-backed model evaluation in protected code | `planned` | LLM assistance cannot yet be invoked through an Orgmetra-owned, auditable draft-evidence boundary. | +| Search, semantic chunking, and image understanding | Architecture mentions derived search/vector storage, but no owned schema, chunker, OCR/object metadata, or index adapter is present | `planned` | Evidence retrieval cannot yet preserve paragraph/DOM/image location semantics for customer search. | +| Hot-partition scale strategy | No `PARTITION BY`/partition-management contract in the current migrations | `planned` | Append-heavy audit/outbox and temporal tables need a tested scale plan before high-volume production. | +| CSAP/SOC 2 evidence package | Security, threat, operability, and test documents exist; no control-evidence collection or attestation exists | `accepted_architecture` | The design is compliance-ready in intent, not a certification or audit report. | +| Release artifact | Root package is `0.1.0`; changelog remains `[Unreleased]`; no protected product release was verified | `planned` | Customers have no versioned, supportable Orgmetra product release yet. | + +## Local candidate artifact outside protected truth + +The current checkout contains `apps/hr-workspace/`, a dependency-free HR Home +and Employee Profile fixture based on Figma nodes `1:10` and `1:28`, plus +host-injected People and Job Analysis API-bound read views. It uses +the shared design tokens and proves navigation, focus-visible styling, +keyboard-accessible evidence and confirmation dialogs, purpose-bound +permission denial, exact allocation values, and English/Korean labels. The +fixture explicitly displays that the protected People API is not connected. +The Job Analysis view requires a host-injected API base URL and authorization +provider, sends the existing purpose header, and has no synthetic fallback or +browser credential storage. The same active PR includes a local Storybook runtime with tokenized stories and a three-test Chromium Playwright contract; +the current head passed the Storybook build and browser contract, but those +tests intercept host-injected reads and do not prove a connected People API, +hosted deployment, or protected-develop truth. The artifact must be reviewed, +checked, and merged independently before P0-1 can change maturity. + +## Buyer gap backlog + +| ID | Priority and owner | Gap and smallest acceptable closure evidence | Dependency | +|---|---|---|---| +| P0-1 | Product / Web | Review and merge the active HR Home + Employee Profile fixture and local Storybook states, then connect it to the protected People API and prove keyboard/focus/permission/confirmation states, exact-value tables, i18n, and browser E2E. | Protected People API evidence | +| P0-2 | Job Architecture | Protected `develop` now contains PR #38's persisted Job Analysis case/API, migration owner, ADR, versioned source evidence, and PostgreSQL acceptance tests. Active PR #53 adds the host-injected read-only browser boundary; connect it to a real API runtime, SME approval path, deployment, and browser evidence. | Protected People API evidence; active workspace path | +| P0-3 | Workforce Validation / scientific owner | Advance active PR #57 into a Rust-first estimator boundary or versioned adapter to `fast-mlsirm`/TEPP. Publish true-parameter recovery, bias, MAE, RMSE, coverage, convergence, temporal, multilevel, multiple-membership, CPU reference, and material GPU parity evidence. | Protected P0-2 and external contract re-resolution | +| P0-4 | Release / Platform | Produce a deployable release with version, changelog, migration inventory, rollback/recovery evidence, support runbook, and exact commit provenance. | P0-1 through P0-3 | +| P1-1 | Integration Hub | Implement contextual-orchestrator adapter for draft evidence only. Pin model/provider/config/evidence digests, use `NVIDIA_NIM_API_KEY` for model-backed development, and record ablations for single-route versus multi-agent depth/access lists. | P0-2; external runtime contract | +| P1-2 | Evidence Platform | Add normalized document/image segment metadata: semantic unit, source location, OCR/object tags, image reference, sensitivity, retention, embedding model/version, and owner provenance. Query filters must run before similarity ranking. | P0-2; document owner contracts | +| P1-3 | Data Platform | Define and rehearse hot-partition strategy for append-heavy audit/outbox and temporal facts, including tenant/time key choice, partition creation, retention, reindexing, and cross-partition query tests. | P0-1; production volume evidence | +| P1-4 | Trust / Operability | Build a CSAP/SOC 2 control matrix with owner, control activity, evidence location, retention, incident path, and release approval. Label it readiness evidence, never certification. | P0-1/P0-2 | + +## Current open PR inventory and integration order + +The following is the current GitHub inventory checked on 2026-08-21. All listed PRs target `develop@9e3e4847510e1e612b48474ba42b177b8ed824df`. `REVIEW_REQUIRED` means the GitHub listing reported that review gate; it is not approval evidence. No self-approval or protection bypass is permitted. + +| PR | Head branch / exact head | Scope | Current state | Next action | +|---:|---|---|---|---| +| 57 | `feat/validation-analysis-handoff` / `081942a723c2ae2cb9bb98a8ffd0b33b72a8bd74` | Governed selection-validity analysis handoff | Draft; merge state `BLOCKED`; `REVIEW_REQUIRED`; no submitted review; current workflows queued | Review the handoff boundary and keep estimator claims separate until exact-head checks and independent approval exist. | +| 56 | `feat/organization-hierarchy-snapshot` / `0eaa8c940842b3ba0d491f72ca57d4333c2c4d12` | Bitemporal organization hierarchy snapshot evidence | Draft; merge state `BLOCKED`; `REVIEW_REQUIRED`; no submitted review; current workflows queued | Verify tenant/time semantics and current-head checks before independent approval. | +| 55 | `fix/people-read-auth-backend-failure` / `f22225700723b46625372844a06205c3dc9b46e4` | People-read error normalization and pre-auth resource budgets | Draft; merge state `BLOCKED`; `REVIEW_REQUIRED`; current workflows queued | Strix's valid MEDIUM hire-route resource-boundary finding is repaired on this head; await terminal People API/security/recovery checks and independent approval. | +| 54 | `feat/workforce-composition-change` / `7d50e77d55bd908975754739f7f5f7e9422334c5` | Same-cutoff workforce composition change evidence | Ready; merge state `BLOCKED`; historical review threads resolved/outdated; no qualifying approval; current workflows queued | Re-fetch exact head, terminal checks, and qualifying independent approval before protected merge. | +| 53 | `codex/product-gap-baseline-workspace` / `c45a8a53125a6075f5edb4a33e02661df4c5d1b5` | HR Home + Employee Profile fixture, host-injected People and Job Analysis API-bound read views, Storybook, Chromium browser contract, reproducible Python service `uv` setup, offer-approval integration, and baseline repair | Draft; merge state `BLOCKED`; `REVIEW_REQUIRED`; no submitted review; current workflows queued | Keep the fixture/API boundaries explicit, wait for all current-head checks, obtain independent approval, then decide whether to merge the product-surface slice. | +| 52 | `feat/tepp-analysis-adapter` / `3690e11516443ee82be88e69b042b5e0dbec80f5` | Governed TEPP analysis request boundary | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review thread resolved/outdated; current workflows queued | Keep non-executing and evidence-bound; merge only after exact-head checks and qualifying review. | +| 51 | `docs/protected-truth-refresh` / `b67a658cc98d58347db4995aba4858f0547ffccc` | Protected product-truth documentation repair | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review threads resolved/outdated; current workflows queued | Reconcile documentation with protected runtime truth, then use current-head checks and independent review. | +| 48 | `feat/governed-compensation-change-review` / `4d40a0d75cb3bba14e388f88bb418404540970b3` | Compensation review packet | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; no current review thread; current workflows queued | Verify high-impact confirmation/evidence boundaries, then merge only with terminal checks and independent approval. | +| 47 | `feat/governed-employment-leave-review` / `9ff50ca3eecfbd65d1b310ae783fc78ef5c1ba09` | Employment leave review packet | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; no current review thread; current workflows queued | Verify temporal and authorization contracts before protected merge. | +| 46 | `feat/governed-employment-separation-review` / `3e436f314c6fe256433db6cd3256e8eed3d6fed2` | Employment separation review packet | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review thread resolved/outdated; current workflows queued | Verify irreversible-action confirmation and audit evidence before protected merge. | +| 45 | `feat/governed-assignment-change-review` / `d89f82fb919039b57ea7f42993708961b7020299` | Assignment change review packet | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review threads resolved/outdated; current workflows queued | Verify tenant/person/employment/position binding before protected merge. | +| 44 | `feat/governed-performance-review` / `a8f319731f1f15f5ae391eb2178f4a642c150548` | Performance review packet | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review threads resolved/outdated; current workflows queued | Verify criterion scope and human confirmation before protected merge. | +| 42 | `feat/selection-outcome-monitoring-plan` / `ea8f62ab44b535b2d71bf6fa874b757bb777b72d` | Selection outcome monitoring | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; no current review thread; current workflows queued | Verify monitoring scope and temporal cohort semantics before protected merge. | +| 40 | `feat/structured-interview-plan` / `11838bcc88fd8afcc37ab0cbe3c6d8c5d8f19344` | Governed structured interview plan | Ready; merge state `BLOCKED`; `REVIEW_REQUIRED`; historical review threads resolved/outdated; current workflows queued | Verify human review, evidence versioning, and current-head checks before protected merge. | + +No open GitHub Issue was returned by the current `gh issue list` query. This does not mean product work is exhausted: the backlog above is derived from protected runtime gaps and is intentionally independent of issue presence. + +## Operating scheduler boundary + +The review/repair/merge sweep is centrally owned by +[`ContextualWisdomLab/.github`](https://github.com/ContextualWisdomLab/.github/blob/main/.github/workflows/pr-review-merge-scheduler.yml), not copied into Orgmetra. The live central `main` workflow currently exposes `*/15` and `*/30` GitHub Actions sweeps, which is more frequent than the hourly operating contract below. Its organization sweep dispatches target-repository scans while target checks still execute against the target repository's exact head. Orgmetra therefore has no repository-local privileged scheduler or model credential path; this is an accepted control-plane boundary, not evidence that any individual PR is merge-ready. + +## Loop contract + +Every central scheduler sweep performs the same bounded sequence: + +1. Re-fetch the protected `develop` head and current open PR list. +2. For each open PR, inspect current review threads, exact head, mergeability, and all repository/security/recovery/coverage checks. +3. If a review comment identifies a defect, reproduce it on the exact head, make the smallest root-cause repair, and re-run the full affected suite. +4. Never transfer checks or approvals from a predecessor head. Never self-approve, bypass protection, cancel a pending gate to create a result, or call an unmerged PR shipped. +5. Merge only when the current head, current base, required checks, resolved threads, and independent approval satisfy live repository rules. Record the merge SHA and continue to the next dependency-ready lane. +6. If no PR is merge-ready, advance the highest-priority unblocked product gap and leave a verifiable branch/PR artifact. +7. Re-run `npm run validate`, the affected `uv` package suite, PostgreSQL contracts, and browser evidence before release claims. + +The loop is an operating procedure, not evidence of completion. Its next customer action must always be explicit: approve, review, correct, request evidence, compare, export, or escalate. + +## Standards and research alignment + +- ISO 30405:2023 grounds the recruitment lifecycle and the requirement to connect preparation, assessment, stakeholders, review, and learning. +- EEOC Uniform Guidelines and SIOP validity guidance ground job-related selection evidence and prohibit treating a statistical link as sufficient without job scope, criterion integrity, and human governance. +- NIST AI RMF 1.0 requires continuous governance, mapping, measurement, and management of AI risks; Orgmetra therefore keeps LLM output as draft evidence and requires human authority. +- AICPA Trust Services Criteria provide the SOC 2 readiness vocabulary for security, availability, processing integrity, confidentiality, and privacy; Orgmetra has readiness documentation but no attestation claim. +- WCAG 2.2 is the target UI baseline. The existing Figma file and design tokens are inputs; the missing evidence is executable accessibility and interaction testing. +- Fugu, Conductor, and TRINITY support evaluating when a single route is enough and when role-specialized multi-agent depth, recursion, and access lists improve evidence work. Orgmetra must measure this through contextual-orchestrator artifacts rather than assuming multi-agent quality. + +The complete APA 7 bibliography is in `docs/doctoring/REFERENCES.md`. + +## Fresh local evidence + +| Check | Result | +|---|---| +| Protected `develop` contents | `git ls-tree` at `9e3e4847510e1e612b48474ba42b177b8ed824df` contains migration `0013`, Job Analysis API, ADR `0014`, candidate-evidence package, ADR `0025`, the protected offer-approval package, and their quality workflows. This proves repository presence, not deployment. | +| `npm run validate` on active PR #53 | Passed: foundation validation and 62 Node tests on exact local head `c45a8a53125a6075f5edb4a33e02661df4c5d1b5`. | +| Earlier Python package matrix | Exact local head `c2d3a6c2804ab5a3e17e454312eddc2f96f2a72f`: HRIS kernel 171 passed; candidate-evidence 75 passed; offer-approval 84 passed. All owned statement and branch coverage reports were 100%. Current exact-head service results are listed below. | +| Storybook and browser fixture | Storybook `10.5.10` production build and `npm run test:e2e` passed on exact local head `c45a8a53125a6075f5edb4a33e02661df4c5d1b5`; Chromium `1.62.1` covered human-review/permission/confirmation/i18n states, host-injected People and Job Analysis reads, authorization/purpose request data, and denied-read no-fallback behavior. Routes are locally intercepted, so connected protected deployment evidence remains open. | +| External pinned validity smoke | At exact read-only `fast-mlsirm` revision `04d0bc21a2a20693bcf16108cd76d394fe844d23`, a local simulation→Rust fit returned `MLS2PLM`, shape `(500, 16)`, backend `rust`, device `auto`, `max_iter_reached` at 101 iterations, and nontrivial recovery error (`parameter_rmse_mean` 2.9606; `gamma_abs_error` 0.9058). This is exploratory external evidence only: no Orgmetra estimator, acceptance study, GPU parity, or protected runtime is claimed. | +| Current exact-head service and PostgreSQL validation | On exact local head `c45a8a53125a6075f5edb4a33e02661df4c5d1b5`, `uv run --project services/people-api --extra test pytest services/people-api/tests` passed 146 tests and `uv run --project services/job-analysis-api --extra test pytest services/job-analysis-api/tests` passed 69 tests, each with 100% owned statement and branch coverage. Both services now have project-local source mappings and checked `uv.lock` files; Job Analysis additionally has corrected Python compatibility metadata and test extras. No manual `PYTHONPATH` was required. Disposable PostgreSQL `16.14` runs passed `test_job_analysis_snapshot_postgres.sh` and `test_people_mutation_idempotency_postgres.sh`; these are local contract evidence, not hosted terminal gates or deployment proof. | +| Protected-tree preservation | `git diff --name-status origin/develop..HEAD --diff-filter=D` returned zero deleted paths; protected Job Analysis migration/API/OpenAPI/quality-contract files remain present on the active PR branch. | +| PostgreSQL contracts | `tests/test_job_analysis_snapshot_postgres.sh` passed on exact local head `c2d3a6c2804ab5a3e17e454312eddc2f96f2a72f` against disposable PostgreSQL `16.14`; the full hosted PostgreSQL matrix remains the authoritative release gate. | + +These results prove the current foundation contracts and a local browser contract. They do not prove that open PRs are merged, that a connected or released browser UI exists, that a statistical estimator exists, or that Orgmetra is certified under CSAP/SOC 2. diff --git a/manifest.json b/manifest.json index 97f2bab14..85e52e3e4 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1,559 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"32cc4ef78d1eca557fa01731026840be01211a043eb0ada552e4e6cb9eace353","bytes":17295,"lines":76},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{ + "package": "orgmetra-foundation-pack", + "version": "0.1.0", + "generated_for_branch": "develop", + "files": [ + { + "path": ".github/workflows/foundation-ci.yml", + "sha256": "7f664425d1307c21f7d26bea40553426b434d141fa2fedaf5ea25e798247878d", + "bytes": 4506, + "lines": 127 + }, + { + "path": ".github/workflows/hr-workspace-browser-e2e.yml", + "sha256": "62be846657a26725f0381cf8c8c679b5d5da7996b25636230ce11ef6f1805740", + "bytes": 1788, + "lines": 57 + }, + { + "path": ".github/workflows/job-analysis-api-quality.yml", + "sha256": "352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a", + "bytes": 4159, + "lines": 105 + }, + { + "path": ".gitignore", + "sha256": "251c57f25b9fd862b3a914aa52987474ec5bc9660d8071d1aa7f1141ea103ca1", + "bytes": 439, + "lines": 41 + }, + { + "path": ".storybook/main.js", + "sha256": "210d8108637ccea90d2c52e2eec793a9215cc512012a2292ab4abf50983a134d", + "bytes": 253, + "lines": 8 + }, + { + "path": ".storybook/preview.js", + "sha256": "0f02687d3c76745afea6402607b06b893a0e88f8414dba4d79e39f50f4d17817", + "bytes": 336, + "lines": 13 + }, + { + "path": "AGENTS.md", + "sha256": "28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16", + "bytes": 2246, + "lines": 34 + }, + { + "path": "ARCHITECTURE.md", + "sha256": "bddc0023259306f2b9de2a67160aa5523d140270691ba42816c34c362e342d7d", + "bytes": 7809, + "lines": 107 + }, + { + "path": "CHANGELOG.md", + "sha256": "608ade458c3db8492fc3b5c212f44cb94b9f3ec4b6acfa4c01c9b8065adae9c2", + "bytes": 18559, + "lines": 83 + }, + { + "path": "CLAUDE.md", + "sha256": "add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f", + "bytes": 1229, + "lines": 20 + }, + { + "path": "LICENSE", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358, + "lines": 202 + }, + { + "path": "NOTICE", + "sha256": "34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042", + "bytes": 305, + "lines": 4 + }, + { + "path": "README.md", + "sha256": "8c4d750a3815d86fb2a8d33eb1c905b014c16740a99130a94ff53954574c5caf", + "bytes": 4046, + "lines": 82 + }, + { + "path": "apps/hr-workspace/app.js", + "sha256": "67cf52bb9104227d32572357c49cebf636494d6fc66fb440f2e415414876b74e", + "bytes": 29937, + "lines": 446 + }, + { + "path": "apps/hr-workspace/index.html", + "sha256": "557f19fd223eb530eddf44280579e80c433b4cca2e95c048d3ef2a473647ee90", + "bytes": 19997, + "lines": 160 + }, + { + "path": "apps/hr-workspace/styles.css", + "sha256": "3751c1abbd8863040cdf61adf65a4fee9d00f78a9848e4a6b01a71b06b961926", + "bytes": 10731, + "lines": 122 + }, + { + "path": "apps/hr-workspace/workspace.stories.js", + "sha256": "b4e2820c3aa5e08bde95592c3d47012eecc8d3f968fe511231f2e258124d7ee5", + "bytes": 7641, + "lines": 134 + }, + { + "path": "database/migrations/0001_foundation_schema.sql", + "sha256": "ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd", + "bytes": 38747, + "lines": 916 + }, + { + "path": "database/migrations/0002_sealed_evidence_digest.sql", + "sha256": "93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c", + "bytes": 6649, + "lines": 202 + }, + { + "path": "database/migrations/0003_audit_outbox_persistence.sql", + "sha256": "2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc", + "bytes": 15417, + "lines": 423 + }, + { + "path": "database/migrations/0004_outbox_delivery_claim.sql", + "sha256": "d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef", + "bytes": 9451, + "lines": 234 + }, + { + "path": "database/migrations/0005_outbox_delivery_finalization.sql", + "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", + "bytes": 6125, + "lines": 170 + }, + { + "path": "database/migrations/0006_outbox_delivery_dead_letter.sql", + "sha256": "c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7", + "bytes": 24919, + "lines": 628 + }, + { + "path": "database/migrations/0007_outbox_retry_exhaustion.sql", + "sha256": "812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5", + "bytes": 19081, + "lines": 476 + }, + { + "path": "database/migrations/0008_audit_outbox_review_hardening.sql", + "sha256": "c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b", + "bytes": 17562, + "lines": 448 + }, + { + "path": "database/migrations/0009_candidate_worker_conversion_governance.sql", + "sha256": "4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9", + "bytes": 11537, + "lines": 281 + }, + { + "path": "database/migrations/0010_validity_study_case_integrity.sql", + "sha256": "3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1", + "bytes": 11979, + "lines": 313 + }, + { + "path": "database/migrations/0011_criterion_observation_scope.sql", + "sha256": "f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9", + "bytes": 7444, + "lines": 165 + }, + { + "path": "database/migrations/0012_people_mutation_idempotency.sql", + "sha256": "52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69", + "bytes": 3162, + "lines": 76 + }, + { + "path": "database/migrations/0013_job_analysis_snapshot.sql", + "sha256": "b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee", + "bytes": 12713, + "lines": 260 + }, + { + "path": "docs/API_CONTRACT.md", + "sha256": "63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589", + "bytes": 4555, + "lines": 76 + }, + { + "path": "docs/DATA_MODEL.md", + "sha256": "6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a", + "bytes": 13366, + "lines": 85 + }, + { + "path": "docs/ERD.md", + "sha256": "546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe", + "bytes": 6964, + "lines": 70 + }, + { + "path": "docs/OPERABILITY.md", + "sha256": "82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62", + "bytes": 11189, + "lines": 71 + }, + { + "path": "docs/PRD.md", + "sha256": "bf73c0ae68f19a24beebd8a43b2e2888ad2e6844697aab8ab5ada59f6c8d87d5", + "bytes": 5852, + "lines": 117 + }, + { + "path": "docs/SECURITY.md", + "sha256": "01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac", + "bytes": 11185, + "lines": 64 + }, + { + "path": "docs/STORYBOARD.md", + "sha256": "6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2", + "bytes": 1342, + "lines": 28 + }, + { + "path": "docs/STORYBOOK.md", + "sha256": "5784f5937e2e66769dbcf73af001be7d12dfd11eca7356f08ab6d85a52568ce2", + "bytes": 3528, + "lines": 85 + }, + { + "path": "docs/TEST_STRATEGY.md", + "sha256": "3fd9e7c058d473f9a6ba236ef77265e388b0e3ab07358fd68414136cdb9b78ec", + "bytes": 17473, + "lines": 151 + }, + { + "path": "docs/THREAT_MODEL.md", + "sha256": "f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252", + "bytes": 6736, + "lines": 23 + }, + { + "path": "docs/TRACEABILITY.md", + "sha256": "7a1301871485181875cd1ef86711659bef575d55267ca74769677bd860dff474", + "bytes": 11987, + "lines": 42 + }, + { + "path": "docs/TRD.md", + "sha256": "23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077", + "bytes": 9064, + "lines": 101 + }, + { + "path": "docs/UML.md", + "sha256": "fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9", + "bytes": 5528, + "lines": 122 + }, + { + "path": "docs/USER_STORIES.md", + "sha256": "5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f", + "bytes": 2670, + "lines": 37 + }, + { + "path": "docs/WIREFRAMES.md", + "sha256": "50b9d2737ed88636fc416e1ae6c22b9258a7b5fff80e233f06c5e4cdd3f58099", + "bytes": 2994, + "lines": 87 + }, + { + "path": "docs/adr/0001-orgmetra-authoritative-hris-record.md", + "sha256": "0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572", + "bytes": 6108, + "lines": 53 + }, + { + "path": "docs/adr/0002-federated-cwl-integration-boundaries.md", + "sha256": "b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2", + "bytes": 4072, + "lines": 44 + }, + { + "path": "docs/adr/0003-bitemporal-hris-data-contract.md", + "sha256": "d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799", + "bytes": 4453, + "lines": 47 + }, + { + "path": "docs/adr/0004-employment-position-version-and-assignment-binding.md", + "sha256": "fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182", + "bytes": 1872, + "lines": 30 + }, + { + "path": "docs/adr/0005-exclusive-employment-and-staffable-seats.md", + "sha256": "10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b", + "bytes": 2091, + "lines": 34 + }, + { + "path": "docs/adr/0006-governed-audit-outbox-envelope.md", + "sha256": "58a460f3d25d125c8fc683f5a37616bb6f81eaf897d7eb70572d092eafc02a28", + "bytes": 14185, + "lines": 67 + }, + { + "path": "docs/adr/0007-governed-job-analysis-evidence.md", + "sha256": "be665cb6132fd8acd60c00623b1f69fce97d2b301e0c87df3a0925643459c0e3", + "bytes": 5605, + "lines": 57 + }, + { + "path": "docs/adr/0008-purpose-bound-pii-authorization.md", + "sha256": "c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7", + "bytes": 5988, + "lines": 55 + }, + { + "path": "docs/adr/0009-performance-criterion-observation-scope.md", + "sha256": "1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64", + "bytes": 7057, + "lines": 57 + }, + { + "path": "docs/adr/0010-naruon-calendar-intent-boundary.md", + "sha256": "0d79e9cce84d3f15ffbe88c42840690616d278a0e999dcef4b7ea19ec7c813cb", + "bytes": 3921, + "lines": 37 + }, + { + "path": "docs/adr/0011-bitemporal-workforce-composition.md", + "sha256": "21bcf0b904c1ddbed74b5e4fa72d553dc30b8bc08abe257ad164ba15f55ad46b", + "bytes": 5568, + "lines": 55 + }, + { + "path": "docs/adr/0012-governed-migration-handoff.md", + "sha256": "ae66a4aa61a34bcee8309a3c34c3d1d440574a55ab536c756b7fb9a5a96ac928", + "bytes": 5973, + "lines": 61 + }, + { + "path": "docs/adr/0013-governed-requisition-review-packet.md", + "sha256": "70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802", + "bytes": 4693, + "lines": 46 + }, + { + "path": "docs/adr/0014-job-analysis-snapshot-persistence.md", + "sha256": "a3d7e8c2234d48183433b0d06795534a8ef8b2d7b6298bed5574e088ebdae656", + "bytes": 5333, + "lines": 49 + }, + { + "path": "docs/adr/0026-product-technical-gap-baseline.md", + "sha256": "6d3f463e1601b0a6d5c9f404a8f866aa5ec7ea30b512b2c5251dfb5c3f42b3b4", + "bytes": 3133, + "lines": 32 + }, + { + "path": "docs/adr/README.md", + "sha256": "f25a8f52936bf02182545f1a91b897fabba5debd272e80f0260757b7a33d5c41", + "bytes": 2697, + "lines": 23 + }, + { + "path": "docs/doctoring/REFERENCES.md", + "sha256": "ad91cae6bb2d8b1fc3f89ffc1657e234173fffa4f7205c6824d9b21da0e77031", + "bytes": 7344, + "lines": 85 + }, + { + "path": "docs/product-technical-gap-baseline.md", + "sha256": "70acfa001c59eef400ea29b0e6cffadef04f0638a3ae5eb346c719dfeeed9818", + "bytes": 25424, + "lines": 162 + }, + { + "path": "docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md", + "sha256": "b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd", + "bytes": 8227, + "lines": 226 + }, + { + "path": "docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md", + "sha256": "4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d", + "bytes": 6237, + "lines": 187 + }, + { + "path": "package-lock.json", + "sha256": "7f737a6adf592e4b9370abbe7de08599a7038e234f8db13aba020fbc0ba80734", + "bytes": 107967, + "lines": 3284 + }, + { + "path": "package.json", + "sha256": "38b16090f937da29531dbe3c5d5f4392c4a8dc2d485b95e43d9bbdf26c7a9a07", + "bytes": 761, + "lines": 19 + }, + { + "path": "packages/hris-kernel/src/orgmetra_hris_kernel/audit.py", + "sha256": "3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190", + "bytes": 7707, + "lines": 160 + }, + { + "path": "packages/hris-kernel/tests/test_audit_outbox.py", + "sha256": "5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c", + "bytes": 7556, + "lines": 200 + }, + { + "path": "playwright.config.mjs", + "sha256": "dd0dc60b82e7cc620b74e3e7649ccf94e6046fc0150c28ee6be7f3d4f5ddd3e3", + "bytes": 920, + "lines": 34 + }, + { + "path": "schemas/openapi.yaml", + "sha256": "09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f", + "bytes": 29503, + "lines": 1020 + }, + { + "path": "scripts/foundation-contract-core.mjs", + "sha256": "fe743c4e9e1589b3c99c28e4c05aeedfa8433017061664d63fa57606a651f8c3", + "bytes": 28673, + "lines": 703 + }, + { + "path": "scripts/foundation-contract.mjs", + "sha256": "5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a", + "bytes": 218, + "lines": 6 + }, + { + "path": "tests/dispatcher-inventory.test.mjs", + "sha256": "09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261", + "bytes": 1597, + "lines": 34 + }, + { + "path": "tests/e2e/hr-workspace.spec.mjs", + "sha256": "843547ce03c366cfa6c99d89a04f1a0d075e3debb898a7f082d1e8454af69ee6", + "bytes": 12514, + "lines": 274 + }, + { + "path": "tests/foundation-contract.test.mjs", + "sha256": "e6fdc19a3f2fa32182d1ecf96ed21df6841c376e3b86494c4f4313564f75c2a4", + "bytes": 15237, + "lines": 395 + }, + { + "path": "tests/hr-workspace.test.mjs", + "sha256": "20c20e565c6634d2f6875d459ff639b0e174d463ed59e46c862df88b4e6327a8", + "bytes": 6148, + "lines": 138 + }, + { + "path": "tests/openapi-contract.test.mjs", + "sha256": "80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc", + "bytes": 6438, + "lines": 195 + }, + { + "path": "tests/test_audit_outbox_hardening_postgres.sh", + "sha256": "518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0", + "bytes": 13396, + "lines": 333 + }, + { + "path": "tests/test_audit_outbox_postgres.sh", + "sha256": "e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2", + "bytes": 13443, + "lines": 357 + }, + { + "path": "tests/test_bitemporal_postgres.sh", + "sha256": "7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc", + "bytes": 8209, + "lines": 230 + }, + { + "path": "tests/test_candidate_worker_conversion_postgres.sh", + "sha256": "681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90", + "bytes": 14673, + "lines": 344 + }, + { + "path": "tests/test_criterion_observation_scope_postgres.sh", + "sha256": "0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d", + "bytes": 17811, + "lines": 469 + }, + { + "path": "tests/test_evidence_sealing_postgres.sh", + "sha256": "57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7", + "bytes": 11349, + "lines": 370 + }, + { + "path": "tests/test_job_analysis_snapshot_postgres.sh", + "sha256": "ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f", + "bytes": 13542, + "lines": 296 + }, + { + "path": "tests/test_operational_uuid_postgres.sh", + "sha256": "7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7", + "bytes": 3346, + "lines": 101 + }, + { + "path": "tests/test_outbox_claim_postgres.sh", + "sha256": "1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b", + "bytes": 14817, + "lines": 429 + }, + { + "path": "tests/test_outbox_dead_letter_postgres.sh", + "sha256": "0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d", + "bytes": 14008, + "lines": 377 + }, + { + "path": "tests/test_people_mutation_idempotency_postgres.sh", + "sha256": "3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5", + "bytes": 16191, + "lines": 381 + }, + { + "path": "tests/test_tenant_isolation_postgres.sh", + "sha256": "dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a", + "bytes": 15134, + "lines": 388 + }, + { + "path": "tests/test_validity_study_case_postgres.sh", + "sha256": "0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02", + "bytes": 14708, + "lines": 301 + }, + { + "path": "tests/validate_repository.py", + "sha256": "4b1ab51c21bd8eadd36c9aad03797c081fdd324c3550b63cda37e10a6ec14cea", + "bytes": 27817, + "lines": 653 + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 73c9101ac..d451f61a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,3283 @@ { - "name": "@contextualwisdomlab/orgmetra", - "version": "0.0.0", + "name": "orgmetra-foundation-pack", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@contextualwisdomlab/orgmetra", - "version": "0.0.0", + "name": "orgmetra-foundation-pack", + "version": "0.1.0", + "devDependencies": { + "@playwright/test": "^1.62.1", + "@storybook/web-components-vite": "^10.5.10", + "storybook": "^10.5.10" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", + "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", + "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.127.0.tgz", + "integrity": "sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.127.0.tgz", + "integrity": "sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.127.0.tgz", + "integrity": "sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.127.0.tgz", + "integrity": "sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.127.0.tgz", + "integrity": "sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.127.0.tgz", + "integrity": "sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.127.0.tgz", + "integrity": "sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.127.0.tgz", + "integrity": "sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.127.0.tgz", + "integrity": "sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.127.0.tgz", + "integrity": "sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.127.0.tgz", + "integrity": "sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.127.0.tgz", + "integrity": "sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.127.0.tgz", + "integrity": "sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.127.0.tgz", + "integrity": "sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.127.0.tgz", + "integrity": "sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.127.0.tgz", + "integrity": "sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.127.0.tgz", + "integrity": "sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.127.0.tgz", + "integrity": "sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.127.0.tgz", + "integrity": "sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.127.0.tgz", + "integrity": "sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxc-resolver/binding-android-arm-eabi": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.21.2.tgz", + "integrity": "sha512-xQoCRv+gKax9KTdwdaQNnAFOai8neay7g3jExDIORzhbrejwGSJaZNTdOJHR5ziLg2joMxOCMOFMo4zuxza2uQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-android-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.21.2.tgz", + "integrity": "sha512-HF5oiE2L05yInPYCFD/4uxSrEZW4SuIfn99Y6L1xnJnzl066JR+MJs2rIdstw8A2MPlAKH+13dpFPNycjqzvGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.21.2.tgz", + "integrity": "sha512-UX4u49CVCAD8QZNELaW8eMGgMAGwFWYEPbvNsh+3r/gs4NX3KfpiACMVwRQT0EuH3uat9hM5Zl+Ppm9pJD8tgg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-x64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.21.2.tgz", + "integrity": "sha512-J9xPx7YBkrRmJ+xl561ztnMWEc1aOyjEIxBiGX1dVb3u7bGSnfObfcZk+Pd+uM0HZAPNsQ1xvD8j52A/uOSqNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-freebsd-x64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.21.2.tgz", + "integrity": "sha512-fRlt7OvSaQkWj6+EDTVxawVxOlqJB2QSnBfkeCyK4RTvsGctbw3BiH2Tb7DzMs7bikc4BRBpvWP5zF9K8b54Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.21.2.tgz", + "integrity": "sha512-gK+vPUcPQITkGwBKpZGrcDHSlU6eDGl7AQacxS2CEKAZIBHWkOVFeJwLZ4tYnA1acJqRM5lt7yYwPCVqGHIJ7A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.21.2.tgz", + "integrity": "sha512-L/Rgas7SrOKy/z7IH+HxSFRqVO4PuLDKLEGKvnhoCBBq3UJ0YzGBou3qMzaAGgkJwsIvX2pBF+7ojzfUhLiZxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.21.2.tgz", + "integrity": "sha512-CUEYvlX1Fk7E9kUMzuswru1J9HLxMwnpDeQGjQuI4ZH+iNCoa2X9T+pvyzrbsgl7WnIeTFTlNlHsRfVdf5g9/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.21.2.tgz", + "integrity": "sha512-ViN1ZibQyxwC67GpoP33oo+S9UyUnkog13vzQb9+v9bCNvrVzJuk0MRdacjtv/9xfRMVF/eqHFyl8YOeykI10Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.21.2.tgz", + "integrity": "sha512-CU1sCqWnhGqYD5I1HedHk5pujrn7ssDkNB/AEQd/pd3D/EojVSgJUlpbafwIbyhia3PgIfkvdFpRPWSALzVumA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.21.2.tgz", + "integrity": "sha512-jWVyZtIHca4Gb96x7dag+y69vlei7ffjrsveLkmf2ZhqEAz6ZSBnY1GWvgZUaZlwZP62A3xD092BW97Q5VGc+g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.21.2.tgz", + "integrity": "sha512-LF29obFqNgBUgDX7rmUK7M4D0JQG5LxhYzn3xXmECcHU9aQAdWG7NiY052qybtesEdwHQXKNTWYQ7mTsybNvWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.21.2.tgz", + "integrity": "sha512-+NYcm+cCHBbtdQQ3A4phQTSuVRYnNHz7wrl9XRAPEovcdoqi0mb1K5ZOl+jN54ZD+q1zz3V0vltbFJmzecJKmw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.21.2.tgz", + "integrity": "sha512-UQqZDdG2r2HhAOsZEgufkIWHPQ886IUyuJQkoZByvzhW8j51R4UNzGBJFkTiTnLhQnggwJRdJgFWK4uY6ZVIMw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.21.2.tgz", + "integrity": "sha512-3Q9PMRjalWkT6NZ4jfujuqTCFwoWErg3y3BnOgb544B8IMw4PktiwWOigMfOHNRLMghZeJ7hpfpZf4CP7rV7Og==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-openharmony-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.21.2.tgz", + "integrity": "sha512-Eljeq3ndtyKhM+Es8LITi4Zl2htzuRZcrPMF3kMCsrILztvU6AjZ3FuEhHHKobPUB9rMpzLpJP5bDqXI7r+iog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.21.2.tgz", + "integrity": "sha512-HGDbNsIywqc4LxU38+CTJNnB/6BF7rheWOJ259b4eE0aEnelYblC8x+1tEd63bp31fYne63RQz9Jb4yVnC7Yig==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.0", + "@emnapi/runtime": "1.11.0", + "@napi-rs/wasm-runtime": "^1.1.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", + "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", + "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.21.2.tgz", + "integrity": "sha512-iWx25CBEgH49iE9q5coEGI/jb1jl5kkCY9z6U5Og67xCkQ/WFMDc2J5U78+AE91SUxM2NqSLhJC8/PLfWnImww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxc-resolver/binding-win32-x64-msvc": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.21.2.tgz", + "integrity": "sha512-VPoCAhKvCQTlG7vxqaBXcmuvbh77BfnGXj8g0pbvVXpm1F/R8rDVwqIWcEbMzrI1JvJlm8v7T9uMVQb6UctMRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", + "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz", + "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz", + "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz", + "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz", + "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz", + "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz", + "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz", + "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz", + "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz", + "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz", + "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz", + "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz", + "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz", + "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz", + "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@storybook/builder-vite": { + "version": "10.5.10", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.5.10.tgz", + "integrity": "sha512-O4GgIP0tKLRueom3EmU3OaBUHKjNYj+jkOvmTIkn3PYTiWVkCuHqSKEs4ADvRyaQuLH+peHhFe4JtkNC9KbtrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf-plugin": "10.5.10", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^10.5.10", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "10.5.10", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.5.10.tgz", + "integrity": "sha512-TaCLBrqVEr767+w58QDotDUiCTuE5cyRJuRcDlsKQyUIyGBv+lYD3lu8wBiVCYxgIjB/gu9HmqiC+0yx1rHzaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^2.3.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "esbuild": "*", + "rollup": "*", + "storybook": "^10.5.10", + "vite": "*", + "webpack": "*" + }, + "peerDependenciesMeta": { + "esbuild": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-2.1.0.tgz", + "integrity": "sha512-Fxh9vYpX9bQqFeHRiY8h2ApeRGDzRSMLwJwNZ/AIRqnyOKHxRKL+yFe+ctEkVJmuptRE9u1Hrn8ZZNHyfDKKNg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@storybook/web-components": { + "version": "10.5.10", + "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-10.5.10.tgz", + "integrity": "sha512-32l6lUjrJ7SrM71C1Uqc2KvV8DU7dXh0ph1A4sPgmNkFPv7LNPoiaOPH+m0FMQ4QCk3gZHLZQU1Yb2iLvHrvWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "lit": "^2.0.0 || ^3.0.0", + "storybook": "^10.5.10" + } + }, + "node_modules/@storybook/web-components-vite": { + "version": "10.5.10", + "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-10.5.10.tgz", + "integrity": "sha512-dCsfpXCrR5DezLk1zJkN4wtZm7VoVrSsjTJ2sQCTBIGMcQZlbMq+U8FC8rZ5pNd/CxzNKABAJjE3P+jQC3lImw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/builder-vite": "10.5.10", + "@storybook/web-components": "10.5.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^10.5.10", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.5", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.5.tgz", + "integrity": "sha512-FhqjldLTpteueBaKflhNFlMT3+PM0O5fiBUivht6b9CZ1eesJyy7+g3Jr7XwJzt/Hip3ZG5hWwK1MX1FuDiE4w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@webcontainer/env": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz", + "integrity": "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lit": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz", + "integrity": "sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", + "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oxc-parser": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.127.0.tgz", + "integrity": "sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.127.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.127.0", + "@oxc-parser/binding-android-arm64": "0.127.0", + "@oxc-parser/binding-darwin-arm64": "0.127.0", + "@oxc-parser/binding-darwin-x64": "0.127.0", + "@oxc-parser/binding-freebsd-x64": "0.127.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.127.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.127.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.127.0", + "@oxc-parser/binding-linux-arm64-musl": "0.127.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.127.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.127.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.127.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.127.0", + "@oxc-parser/binding-linux-x64-gnu": "0.127.0", + "@oxc-parser/binding-linux-x64-musl": "0.127.0", + "@oxc-parser/binding-openharmony-arm64": "0.127.0", + "@oxc-parser/binding-wasm32-wasi": "0.127.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.127.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.127.0", + "@oxc-parser/binding-win32-x64-msvc": "0.127.0" + } + }, + "node_modules/oxc-resolver": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.21.2.tgz", + "integrity": "sha512-w5tLwYN3Zo24w5EeWJjJWZOwhYqTtC8PS2B1tIt7BZUuqTIcU07sQValbDw+rq7+AuAGzOHklgK+ifsy4lpXfw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-resolver/binding-android-arm-eabi": "11.21.2", + "@oxc-resolver/binding-android-arm64": "11.21.2", + "@oxc-resolver/binding-darwin-arm64": "11.21.2", + "@oxc-resolver/binding-darwin-x64": "11.21.2", + "@oxc-resolver/binding-freebsd-x64": "11.21.2", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.21.2", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.21.2", + "@oxc-resolver/binding-linux-arm64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-arm64-musl": "11.21.2", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-riscv64-musl": "11.21.2", + "@oxc-resolver/binding-linux-s390x-gnu": "11.21.2", + "@oxc-resolver/binding-linux-x64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-x64-musl": "11.21.2", + "@oxc-resolver/binding-openharmony-arm64": "11.21.2", + "@oxc-resolver/binding-wasm32-wasi": "11.21.2", + "@oxc-resolver/binding-win32-arm64-msvc": "11.21.2", + "@oxc-resolver/binding-win32-x64-msvc": "11.21.2" + } + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/recast": { + "version": "0.23.21", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.21.tgz", + "integrity": "sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rolldown": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz", + "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.146.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.5", + "@rolldown/binding-android-arm64": "1.2.5", + "@rolldown/binding-darwin-arm64": "1.2.5", + "@rolldown/binding-darwin-x64": "1.2.5", + "@rolldown/binding-freebsd-x64": "1.2.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.5", + "@rolldown/binding-linux-arm64-gnu": "1.2.5", + "@rolldown/binding-linux-arm64-musl": "1.2.5", + "@rolldown/binding-linux-ppc64-gnu": "1.2.5", + "@rolldown/binding-linux-s390x-gnu": "1.2.5", + "@rolldown/binding-linux-x64-gnu": "1.2.5", + "@rolldown/binding-linux-x64-musl": "1.2.5", + "@rolldown/binding-openharmony-arm64": "1.2.5", + "@rolldown/binding-win32-arm64-msvc": "1.2.5", + "@rolldown/binding-win32-x64-msvc": "1.2.5" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz", + "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/storybook": { + "version": "10.5.10", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.5.10.tgz", + "integrity": "sha512-Rz8k9ejFHsi7lbtJTaxZlhCUz4GkbJIKEoKDjXeLfr/ZhXip73E6keKxW0KH8iGeKiCqHAbJCV4YIQrxTOLiig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/icons": "^2.0.2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/user-event": "^14.6.1", + "@vitest/expect": "3.2.4", + "@vitest/spy": "3.2.4", + "@webcontainer/env": "^1.1.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", + "jsonc-parser": "^3.3.1", + "open": "^10.2.0", + "oxc-parser": "^0.127.0", + "oxc-resolver": "11.21.2", + "recast": "^0.23.5", + "semver": "^7.7.3", + "use-sync-external-store": "^1.5.0", + "ws": "^8.21.1" + }, + "bin": { + "storybook": "dist/bin/dispatcher.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "prettier": "^2 || ^3", + "vite-plus": "^0.1.15 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, "engines": { - "node": ">=22" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index ceb2fb8fc..bb132586c 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,18 @@ "name": "orgmetra-foundation-pack", "version": "0.1.0", "private": true, + "type": "module", "description": "Orgmetra evidence-centered HRIS foundation baseline.", "scripts": { - "validate": "python3 tests/validate_repository.py && node scripts/foundation-contract.mjs && node --test tests/foundation-contract.test.mjs tests/openapi-contract.test.mjs tests/dispatcher-inventory.test.mjs" + "validate": "python3 tests/validate_repository.py && node scripts/foundation-contract.mjs && node --test tests/foundation-contract.test.mjs tests/openapi-contract.test.mjs tests/dispatcher-inventory.test.mjs tests/hr-workspace.test.mjs", + "test:workspace": "node --test tests/hr-workspace.test.mjs", + "test:e2e": "playwright test", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "devDependencies": { + "@playwright/test": "^1.62.1", + "@storybook/web-components-vite": "^10.5.10", + "storybook": "^10.5.10" } } diff --git a/packages/design-tokens/tokens.css b/packages/design-tokens/tokens.css index 26bc9d411..59bbbb726 100644 --- a/packages/design-tokens/tokens.css +++ b/packages/design-tokens/tokens.css @@ -7,6 +7,9 @@ --orgmetra-action-export: #334155; --orgmetra-action-escalate: #b45309; --orgmetra-surface-page: #f8fafc; + --orgmetra-surface-card: #f7faff; + --orgmetra-border-subtle: #d1d9e5; + --orgmetra-focus-ring: #1d4e89; --orgmetra-text-primary: #0f172a; --orgmetra-text-muted: #475569; --orgmetra-danger: #b91c1c; diff --git a/packages/design-tokens/tokens.json b/packages/design-tokens/tokens.json index 3ae4aa15b..2e8573b84 100644 --- a/packages/design-tokens/tokens.json +++ b/packages/design-tokens/tokens.json @@ -11,6 +11,9 @@ "action.export": "#334155", "action.escalate": "#B45309", "surface.page": "#F8FAFC", + "surface.card": "#F7FAFF", + "border.subtle": "#D1D9E5", + "focus.ring": "#1D4E89", "text.primary": "#0F172A", "text.muted": "#475569", "danger": "#B91C1C" diff --git a/playwright.config.mjs b/playwright.config.mjs new file mode 100644 index 000000000..dc23bfb0e --- /dev/null +++ b/playwright.config.mjs @@ -0,0 +1,34 @@ +import { defineConfig, devices } from '@playwright/test'; + +const port = 4173; + +export default defineConfig({ + testDir: './tests/e2e', + timeout: 15_000, + expect: { timeout: 5_000 }, + fullyParallel: false, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: process.env.CI + ? [['line'], ['html', { outputFolder: 'playwright-report', open: 'never' }]] + : 'list', + use: { + baseURL: `http://127.0.0.1:${port}`, + trace: 'retain-on-failure', + screenshot: 'only-on-failure', + video: 'retain-on-failure', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: { + command: `python3 -m http.server ${port} --bind 127.0.0.1`, + url: `http://127.0.0.1:${port}/apps/hr-workspace/index.html`, + reuseExistingServer: !process.env.CI, + timeout: 120_000, + }, +}); diff --git a/scripts/foundation-contract-core.mjs b/scripts/foundation-contract-core.mjs index 1e9fb267c..96d0b376c 100644 --- a/scripts/foundation-contract-core.mjs +++ b/scripts/foundation-contract-core.mjs @@ -20,8 +20,17 @@ export const REQUIRED_FILES = Object.freeze([ 'NOTICE', 'manifest.json', 'package.json', + 'package-lock.json', + '.storybook/main.js', + '.storybook/preview.js', + 'apps/hr-workspace/index.html', + 'apps/hr-workspace/styles.css', + 'apps/hr-workspace/app.js', + 'apps/hr-workspace/workspace.stories.js', '.github/workflows/foundation-ci.yml', '.github/workflows/job-analysis-api-quality.yml', + '.github/workflows/hr-workspace-browser-e2e.yml', + 'playwright.config.mjs', 'docs/PRD.md', 'docs/TRD.md', 'docs/USER_STORIES.md', @@ -37,6 +46,7 @@ export const REQUIRED_FILES = Object.freeze([ 'docs/TEST_STRATEGY.md', 'docs/OPERABILITY.md', 'docs/TRACEABILITY.md', + 'docs/product-technical-gap-baseline.md', 'docs/adr/README.md', 'docs/adr/0001-orgmetra-authoritative-hris-record.md', 'docs/adr/0002-federated-cwl-integration-boundaries.md', @@ -52,6 +62,7 @@ export const REQUIRED_FILES = Object.freeze([ 'docs/adr/0012-governed-migration-handoff.md', 'docs/adr/0013-governed-requisition-review-packet.md', 'docs/adr/0014-job-analysis-snapshot-persistence.md', + 'docs/adr/0026-product-technical-gap-baseline.md', 'docs/doctoring/REFERENCES.md', 'docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md', 'docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md', @@ -75,6 +86,8 @@ export const REQUIRED_FILES = Object.freeze([ 'scripts/foundation-contract.mjs', 'tests/dispatcher-inventory.test.mjs', 'tests/foundation-contract.test.mjs', + 'tests/hr-workspace.test.mjs', + 'tests/e2e/hr-workspace.spec.mjs', 'tests/openapi-contract.test.mjs', 'tests/test_bitemporal_postgres.sh', 'tests/test_tenant_isolation_postgres.sh', @@ -94,6 +107,7 @@ export const REQUIRED_FILES = Object.freeze([ /** Exact maturity vocabulary accepted by traceability tables. */ export const MATURITY_VALUES = Object.freeze(new Set([ + 'implemented_on_protected_develop', 'implemented_on_protected_main', 'implemented_on_active_pr', 'accepted_architecture', diff --git a/services/job-analysis-api/pyproject.toml b/services/job-analysis-api/pyproject.toml index 5e27bf477..0c70550da 100644 --- a/services/job-analysis-api/pyproject.toml +++ b/services/job-analysis-api/pyproject.toml @@ -7,7 +7,7 @@ name = "orgmetra-job-analysis-api" version = "0.1.0" description = "Governed persistence boundary for Orgmetra job-analysis snapshots." readme = "README.md" -requires-python = ">=3.11" +requires-python = ">=3.12" license = { text = "Apache-2.0" } authors = [{ name = "ContextualWisdomLab" }] dependencies = [ @@ -15,6 +15,13 @@ dependencies = [ "orgmetra-keyverse-adapter==0.1.0", ] +[project.optional-dependencies] +test = ["pytest>=8.3", "pytest-cov>=5.0"] + +[tool.uv.sources] +orgmetra-hris-kernel = { path = "../../packages/hris-kernel" } +orgmetra-keyverse-adapter = { path = "../../packages/keyverse-adapter" } + [tool.setuptools] package-dir = {"" = "src"} diff --git a/services/job-analysis-api/uv.lock b/services/job-analysis-api/uv.lock new file mode 100644 index 000000000..0d74575fa --- /dev/null +++ b/services/job-analysis-api/uv.lock @@ -0,0 +1,225 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/c3/4f2195f512fb172aa425a8803a874b2baa9ba7f80ff7b6080998761fc701/coverage-7.15.4.tar.gz", hash = "sha256:0548198fff07ccf4faf469520bce1c2eceb1ce3e62891921138dec10907f9d00", size = 936952, upload-time = "2026-08-06T13:50:24.442Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/48/bc8d4ba7b37551a767bd863f15b3f80182b271c2f55975356f5f7dbe94c2/coverage-7.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4fedd1f7f428f9fe83b1ead5e7cc87a43427be31aadafbac3ac0636dc7abb22", size = 222543, upload-time = "2026-08-06T13:47:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/20/dd/88d6f83f1fffc974a3691a34a97951c5b12df7512a6782c5963883cbc058/coverage-7.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37e2f0cdf58e2e1fed4e4d5a8f8786ae2f7eb80b478016876667dc4a01d60a97", size = 222905, upload-time = "2026-08-06T13:47:38.927Z" }, + { url = "https://files.pythonhosted.org/packages/bd/5c/54ee0d4748585bb0acab9891cd8d92f2d3593165b4e59fc9de113bfb3140/coverage-7.15.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fb55d0e70bb15f2e81477613627286581414693d74ac7963c93a790dd453ca9d", size = 254407, upload-time = "2026-08-06T13:47:40.488Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3f/f0642a372f494bd0d7dad3b497083b910194a5f1c88be2c94fef707c3b59/coverage-7.15.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:899b9da30f3c6c336566e3707495bb23e8302d39d862f01fa78c48b99b9437e2", size = 257145, upload-time = "2026-08-06T13:47:41.931Z" }, + { url = "https://files.pythonhosted.org/packages/71/17/8b46d0ed68251016002ec972c8fc0119961a765d0984cafb8bf317c43758/coverage-7.15.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d15715e8c46552827e5e4f30a35575a2dbcad14454cf3284c54483946bd16931", size = 258257, upload-time = "2026-08-06T13:47:43.527Z" }, + { url = "https://files.pythonhosted.org/packages/30/b8/8498a0e72d0adbe15477dd07463d2b3bb2c9f6a4815e8589e50939e2c3ae/coverage-7.15.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:002a438859f7b430bc99afeaf01a6d187dad1d0dc907b64cdeffc632a5db8fd8", size = 260517, upload-time = "2026-08-06T13:47:45.121Z" }, + { url = "https://files.pythonhosted.org/packages/41/e1/7dce19c3bdb1e3dd63e769508216500edad81bd5f69a26d724e32aceaf78/coverage-7.15.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e4193a04b518f7968f3099755f5509ee7cccc6dc2b92a6b14841934d22e222c9", size = 254785, upload-time = "2026-08-06T13:47:46.541Z" }, + { url = "https://files.pythonhosted.org/packages/dd/b1/e1494703c675a2561723cd9b89f45c9168782c31280c611b1f767851e57c/coverage-7.15.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e98dcc55d572b38e69d117da7e8e8efb8500f1f5eaf81ecd460a63220790b839", size = 256176, upload-time = "2026-08-06T13:47:48.155Z" }, + { url = "https://files.pythonhosted.org/packages/73/76/a5629d270fb638a43a4b10466f51e2f49d532c1aa4da2913cbbb150bbe0a/coverage-7.15.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:af6c538498ce66c10d3fd541c2a8d5b03da5850355add34e6cba564210cb9e72", size = 254321, upload-time = "2026-08-06T13:47:49.757Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/9c44447218435d5766b911534f9d798144a5560f85e9a54ebe5f3f5d19f9/coverage-7.15.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1d10025d96ea89fc2f73714dbc4cbd433fe012c1ac9e23f895d7728b238b6e52", size = 258390, upload-time = "2026-08-06T13:47:51.248Z" }, + { url = "https://files.pythonhosted.org/packages/de/36/c1e127616fb3fa18a9ff71e76c417f2fd7424332a4870015ac224ef4c039/coverage-7.15.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d802e1947603162ded419bff83ac7489820355d2b856dfb09206574e3a37ac0c", size = 253894, upload-time = "2026-08-06T13:47:52.816Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b9/fdb92c8ae7a8bb9b850cc253b7b3b9c8526f68130002048b5671cd510d09/coverage-7.15.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2de40895718f91951b86712b4c5b694acaf9a0a49be13874896f599a1eed3f4", size = 255763, upload-time = "2026-08-06T13:47:54.296Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/a7d51b2587c7bdb76e71b0896d2565bf7d60436b5122fc83e511adb1f7cd/coverage-7.15.4-cp312-cp312-win32.whl", hash = "sha256:5c3431b2161279b7db5c2a1aa58ae02e5cb8c3c42d93a5094be3f5537bd5b11b", size = 224597, upload-time = "2026-08-06T13:47:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/49/b9/5c5f80cc55f5acaaca6dee677626bfcec8c87204a7809b438b08e84f4571/coverage-7.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:6befeab5fb2b51c958ca4ac6c5d141a1e8240f4f76e46350f1911963deda49cd", size = 225135, upload-time = "2026-08-06T13:47:57.52Z" }, + { url = "https://files.pythonhosted.org/packages/47/e4/2a4561f89ff6bf7c925c287d0f2cce8bdf139c3a33735c87e3203401cf94/coverage-7.15.4-cp312-cp312-win_arm64.whl", hash = "sha256:67bc345491ab55b837277d76f5775d057e8c7f1ac44d890d8c2c82adde258c6f", size = 224515, upload-time = "2026-08-06T13:47:58.977Z" }, + { url = "https://files.pythonhosted.org/packages/f1/84/651a9310859673aaa3b3203f1aa1641ca60fcf2494683e1c9474c7172780/coverage-7.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c705b28feb2775dc82a25f1d473a370bc37ff93f5177f4e29ce2425f560f6921", size = 222565, upload-time = "2026-08-06T13:48:00.796Z" }, + { url = "https://files.pythonhosted.org/packages/82/f9/4dcf700137e8af550670f4d74d1b63828ce93e1e2b05e5f10710eb2ea987/coverage-7.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ff205ab5e3ecc670f6a4dd19d9cbf12ede53dd41cfc1e15716ec961ea6d314e", size = 222936, upload-time = "2026-08-06T13:48:02.391Z" }, + { url = "https://files.pythonhosted.org/packages/07/4a/612ff1e780b3fbfd637486f542f84adc5503873d8b5d279dec1ffeef9414/coverage-7.15.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5172326e861a38b48b48befca15e0f477a26b283337a33a739c8fed229934e36", size = 253926, upload-time = "2026-08-06T13:48:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/b0/04/d1cff1c2ead4708a6a79c01d3736b6a25bd38a36678398f72a8dd33dfad9/coverage-7.15.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:12b59c90084e3234fb11184886bf4a40f4f16a8c8f867be2e087b81f8e8868d4", size = 256523, upload-time = "2026-08-06T13:48:05.996Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/d34e13fb4b293cbdb9665838cf5522077b8ad14ef947550631a4bced36a5/coverage-7.15.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349062d66f00b40fa2c1c222438bad25fabf755631b5d82937fe985c8008615c", size = 257759, upload-time = "2026-08-06T13:48:08.036Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e7/2c5fe7636fdb0732fe0f09f308a5b066864078b7fc61f6678e8478554f2e/coverage-7.15.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4256ced708e598e05209bc1a8ab4074e04a51dba4c62fb45926a229af675ace7", size = 259890, upload-time = "2026-08-06T13:48:09.834Z" }, + { url = "https://files.pythonhosted.org/packages/92/28/9689f0858dfff59c2ea688938ab9fa2925631235df67126a42b6c5c70ae1/coverage-7.15.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d80f974b20782d9612c8b4c9beeca867074c7cf4079d1419843fa25a26428b25", size = 254121, upload-time = "2026-08-06T13:48:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/785077c230c157243eb5aa9a26c3be260ecd02001bead54a3cada3df8e03/coverage-7.15.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e179f19bfe1d31f8eeeaa12990194d761c4f62f0759661000bca6cd8729f40b", size = 255891, upload-time = "2026-08-06T13:48:13.209Z" }, + { url = "https://files.pythonhosted.org/packages/d4/90/e20371b17b40f912f21305c2db2f30efa3de306f7320fc916804872c85a4/coverage-7.15.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8bc16bb47b7679670eceff71d78bfb7d6e5b143f6c2cd117487ec7c75e0d4b78", size = 253859, upload-time = "2026-08-06T13:48:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/05/49/25371987ee459a5f67c0427fb75c74f9358e65f2c71fe75bf41c1b6c5fcb/coverage-7.15.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1cd685005cd2c4200adfc14cf39a603b9320efab3f18a8f7f156d20c9cc3345f", size = 258011, upload-time = "2026-08-06T13:48:16.464Z" }, + { url = "https://files.pythonhosted.org/packages/30/6e/32e67467f6154bf4f1c4f63b05acc5097cba4237d45bbeeea446b52e8ac1/coverage-7.15.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:337399ad2c93b3acd2a937627dae8b3e86b66707cd3d3e856347999aadf1ef8d", size = 253676, upload-time = "2026-08-06T13:48:18.493Z" }, + { url = "https://files.pythonhosted.org/packages/03/c1/8b24192e89286399765155251f99ee9f070a9d637109018ac23d99b99f6f/coverage-7.15.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:96e257121228ec5cd2bb919276e94ac11074471bc37d68dbae0e8308cce15fff", size = 255453, upload-time = "2026-08-06T13:48:20.057Z" }, + { url = "https://files.pythonhosted.org/packages/16/6f/8b41ebdf67c87854e17c035336a90f1cfbad0c14c2a584301be6ff148718/coverage-7.15.4-cp313-cp313-win32.whl", hash = "sha256:c65a9e0dfc6143491879da4e13b5e30f8be192055de508d737fb14601edbd22c", size = 224605, upload-time = "2026-08-06T13:48:21.655Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e2/2946c7f0b42b152ecb21ff1bdad72e3d301e790c0c487e4a86e8c9f69347/coverage-7.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:2ff8f5e9b8f7a94f0c11c45631eee103dbcb7d63274edd12c56efe1be690b3b4", size = 225148, upload-time = "2026-08-06T13:48:23.376Z" }, + { url = "https://files.pythonhosted.org/packages/9e/83/3f4a69957f48ae7a0aba76c34743f88963d607b19e03f3f8e66f91cae0f9/coverage-7.15.4-cp313-cp313-win_arm64.whl", hash = "sha256:6e0a8a5083b096487d6cfced94cdd514d8f5db6f113610fb36c0620edb1028cf", size = 224536, upload-time = "2026-08-06T13:48:25.117Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ac/748cf29eeb2d6be34a3176ce26a4f49e38085ee08e8935f05f6f26ed7e0f/coverage-7.15.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:770e9325ab5ea6d56f77e59b29ecfe0ac20b57a82a601876f90494a4dda0386f", size = 222608, upload-time = "2026-08-06T13:48:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/0b/02/1abbf5c984677b0aa439cdacaccbf38d248939d8ef8fe1cc7a50d73edb77/coverage-7.15.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d12b33a3a50a1676b7784dc8d00a0c6d66a9f2add4b85a041c19b6a7e53ef23c", size = 222940, upload-time = "2026-08-06T13:48:28.432Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e1/ff8f9f53d9fcf586125b55d0b1f04ec1c14955fee41e83d5814bee141bb5/coverage-7.15.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5669c8378ebde86f5def7a25d29586631b58acc27ffde04399f678f3dfc6e082", size = 253985, upload-time = "2026-08-06T13:48:29.995Z" }, + { url = "https://files.pythonhosted.org/packages/a1/26/595759762e514e81be1d7d01ed03444303bcd152226a6529998d253f9201/coverage-7.15.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ff97a14362eef486483ed44042ca2027ea257df6ff768e62358ee0c9776925ac", size = 256492, upload-time = "2026-08-06T13:48:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/b79aabac54d482be23b5fcdd4f4662bff24a78edc4ee29201726929936d5/coverage-7.15.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a325e815318638aed1655d9c06e6d7c2d3d46c09231ce988070428a8762d734", size = 257837, upload-time = "2026-08-06T13:48:33.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/0f/bf7f297885a5bf6fd71e5782404e0ff059ca09e8711ceb3a08544abde45a/coverage-7.15.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:474223409d88eb20d2d6a0d37ea60e8647a65a90cc008dc1f0410af5f64f1e0d", size = 260152, upload-time = "2026-08-06T13:48:34.75Z" }, + { url = "https://files.pythonhosted.org/packages/fd/f1/296744e854ff8368542343457414380465e9ceefb9192342feb9d3bc461d/coverage-7.15.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f2f62ae3cd189dd2e13aece758c57b3eecbd27be070dbd4cbd10936049e5dbf", size = 253978, upload-time = "2026-08-06T13:48:36.434Z" }, + { url = "https://files.pythonhosted.org/packages/55/b0/bbdb2e9057493e66220a2e149ca2d301ba0e3a58a83bd6b90de9826d16f3/coverage-7.15.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:39ece820e29e0a2ba34b3ecb3be83c27e997eed8926f2ba6fe7ce7a0bda5843b", size = 255846, upload-time = "2026-08-06T13:48:38.317Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/38015b2b6d21258713bd17e76b59d033b191efb5703589cffd037dfbca20/coverage-7.15.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f21b56dcace11dfe013014201f577dcd592b2a9b72182d930361b47cf6f73f25", size = 253808, upload-time = "2026-08-06T13:48:39.993Z" }, + { url = "https://files.pythonhosted.org/packages/0b/64/0d515c1e60ee6fbfd1a0e79c07cd87d388a233b7adc37758735677203808/coverage-7.15.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:93a3a0b662abcc10c73a47cbc72cd60f63618d6989fb2d1286e50eacd974f303", size = 258081, upload-time = "2026-08-06T13:48:41.971Z" }, + { url = "https://files.pythonhosted.org/packages/91/71/04d9e7a3642146c6351338aef4ef85ab11dbbb54744c13245caba1aad1c0/coverage-7.15.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:141fae2cabf5569b782c10afc4c850ce10f618c13f8db54765cba99cc839da1f", size = 253624, upload-time = "2026-08-06T13:48:43.731Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a7/6c28b74c81ebff66987b0e2522ba5cffa3e90b0c33cb6a2eb264d4ee8cf1/coverage-7.15.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:81294c7e6ab30c5f74c0353b11b2fd6320e72d9bee6ac73b357caa8b916323a5", size = 255280, upload-time = "2026-08-06T13:48:45.58Z" }, + { url = "https://files.pythonhosted.org/packages/52/af/bc19996a7014b98d7bbb0f0939453c67074af65784a3aa16a789a07381fa/coverage-7.15.4-cp314-cp314-win32.whl", hash = "sha256:7bbd7d6418e0dab31a206af5203bd43ae36edb8e7fba1940b055d3e9249290d7", size = 224768, upload-time = "2026-08-06T13:48:47.525Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/219484e476d6e101ba0a444852579e05f5b75c37c611a42ed1190f73ef62/coverage-7.15.4-cp314-cp314-win_amd64.whl", hash = "sha256:f0204ed122758782970526057093f448051a39db9d810d4e344bb87a3546f425", size = 225259, upload-time = "2026-08-06T13:48:49.513Z" }, + { url = "https://files.pythonhosted.org/packages/b7/66/fa77daf4e383e5f776dac62c2409b6af81910ae6fe326bd5170dba74cc63/coverage-7.15.4-cp314-cp314-win_arm64.whl", hash = "sha256:9e71e7bc71c686a123347ae47a0de33a175e797a85bb57b791492adf4eec8ed8", size = 224684, upload-time = "2026-08-06T13:48:51.235Z" }, + { url = "https://files.pythonhosted.org/packages/58/5b/f03bf0ce362bbf3f785fa5219620d00778d4ac6fc9e407734828e9c672f6/coverage-7.15.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7c922735321eef3f87c280a3d39afff6b646723a2880b862cda4ac7a093b8aa8", size = 223338, upload-time = "2026-08-06T13:48:52.896Z" }, + { url = "https://files.pythonhosted.org/packages/0f/76/e77d0ae22501831cc9f92193e8a957a5caa1dd177f90a6d1d9b106242d92/coverage-7.15.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f41c17c4668a655ce96d090d8d5ffdc24ef64b5a02f9753884d08483e8a4a41a", size = 223609, upload-time = "2026-08-06T13:48:54.688Z" }, + { url = "https://files.pythonhosted.org/packages/82/1a/b1f089da8d38ac612fa2dd6dc7f4a1a7657d12f3e261d2996edd3a838d0b/coverage-7.15.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:46822e9b6ff1c6a72b518c162c44a8f45a61a1d609c51084bf5b16c023c5037b", size = 264970, upload-time = "2026-08-06T13:48:56.403Z" }, + { url = "https://files.pythonhosted.org/packages/bf/31/e66d98d6e9c7fcc88470f1e234eaf6b1950dc0dfbf797f7282c1c861da24/coverage-7.15.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d6f4955b73b5445271379a59e3792b0d978f42d4a01e0cf7a67d9c33a3bb0a5", size = 267088, upload-time = "2026-08-06T13:48:58.41Z" }, + { url = "https://files.pythonhosted.org/packages/59/a1/ae94eb2c541add426378408379f233591e069040b1e2cdb33df9498a0682/coverage-7.15.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3fc9e047706fb4a9abb54f719d3aa643e80e5bb3818182c40aee01ac0f0247ba", size = 269508, upload-time = "2026-08-06T13:49:00.42Z" }, + { url = "https://files.pythonhosted.org/packages/9c/c7/88a10694a1c6a213569766aba9f25847b28155d4ac731b13226db216356d/coverage-7.15.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05e491d4f3165d62d4f5c8fd48dfeabf2ae8f42cbbd484319af33ea851b78982", size = 270629, upload-time = "2026-08-06T13:49:02.234Z" }, + { url = "https://files.pythonhosted.org/packages/b3/34/d8b8232e5e55169933b59aabcef2fedfa4b9d8897361bb80fcbda146505f/coverage-7.15.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:226c66e80ec0598d3b9b4874123df167ccca342aca8714f77cac6829688ee09c", size = 264043, upload-time = "2026-08-06T13:49:04.102Z" }, + { url = "https://files.pythonhosted.org/packages/7e/35/58b009dbf8c471c7224716478b9fed4a7e1af15320e1ed41660978504663/coverage-7.15.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac41cc14bebda0dbfb0628036b7f75706935c95bcc07fefe9a0f93614aa60a57", size = 266963, upload-time = "2026-08-06T13:49:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/62/aa/57fbda1b42c892968273c56b6ee9dc0f1310850859230a507bc7873b1f65/coverage-7.15.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8af623e5cd92080acddd02b38f2f406a2c3a0893c38950b211890361448fbf26", size = 264569, upload-time = "2026-08-06T13:49:07.706Z" }, + { url = "https://files.pythonhosted.org/packages/98/8a/360e6e7f24d477b7e889703af0afa878d15b6d4d8d2a822b2835c169a879/coverage-7.15.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07545711d4f0f32852a18f18ad11f76f0109909d09e78b9008b4cfc67e829429", size = 268299, upload-time = "2026-08-06T13:49:09.587Z" }, + { url = "https://files.pythonhosted.org/packages/4e/89/6f701261aee21b6b5fa8f7872229406dc917e125069448292223bf213606/coverage-7.15.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a0865421cfdc53654b342d515e5a233187590882d20b95752150e53f65460017", size = 263413, upload-time = "2026-08-06T13:49:11.604Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0f/6f04036edc260ed425af83e834f627fad48941ce97b50bfe6edd8b6fa623/coverage-7.15.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:460115e32ee40566476db5048f9bec1e842c127ad8e6f8be745aad3ac9cbc839", size = 265725, upload-time = "2026-08-06T13:49:13.38Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ce/d19b5d4d5c49a7bfb925fd74310fee7d28bc99520ac3367ccbc54e662518/coverage-7.15.4-cp314-cp314t-win32.whl", hash = "sha256:cbde877ef9dd7baf272b9bfef2b8a25edd45d9170fc326951dd20eb480335e85", size = 225079, upload-time = "2026-08-06T13:49:15.265Z" }, + { url = "https://files.pythonhosted.org/packages/26/bb/7aa1b3b173faee0679037ca950bbbe1247273656697994d8d13f80f8d4b4/coverage-7.15.4-cp314-cp314t-win_amd64.whl", hash = "sha256:3da9e92d1c551fd7563833e9ade686efb0c4b7363ab7681a94283958c950bf5e", size = 225911, upload-time = "2026-08-06T13:49:17.279Z" }, + { url = "https://files.pythonhosted.org/packages/81/1c/4ea9e47426d80038d9222db3c4534cb6021a74b237d3ff97ffd33b6600dd/coverage-7.15.4-cp314-cp314t-win_arm64.whl", hash = "sha256:3a54f5a0d85050c73a38f6793090ee83974531e67fe5e57a1da9bee11398aa5e", size = 225219, upload-time = "2026-08-06T13:49:19.293Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c4/dc5d2ac8f9142e7ec7de66e7bf0591db29d78955a040bd915870d9c0e657/coverage-7.15.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:2c9872e4d9dc5d3cf616bf4b382f5a00359305a5be666a3dd0b5cdb4e49597f9", size = 222604, upload-time = "2026-08-06T13:49:21.279Z" }, + { url = "https://files.pythonhosted.org/packages/70/39/33e63df81fe2ee100897451841c821467635923e58e37c6bd4b46dd8106c/coverage-7.15.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:e101dbb4b9b72f0cddd8cdc8c9c5b47f456766f5e0ac82dbfb75e5c55409b78a", size = 222944, upload-time = "2026-08-06T13:49:23.187Z" }, + { url = "https://files.pythonhosted.org/packages/99/1f/ef3ffb5557febc75a0d97aa459d0266d7d741110265121cc6d8539343d44/coverage-7.15.4-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7d1abebdb047729e852b9c77a00497dfbeb11eb3a117e037d7dbc3ac8e5f5c54", size = 254050, upload-time = "2026-08-06T13:49:25.008Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f5/1f0f6f77698c3601ca0ae7431e34b24c62ca2f06fecb23b73ed1f651d2be/coverage-7.15.4-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d28a4a899354d0ea6214cc59b4fa19eefbce1b9ff1688ab579acf49e894bd3fb", size = 256967, upload-time = "2026-08-06T13:49:26.896Z" }, + { url = "https://files.pythonhosted.org/packages/03/7a/2ed9bed79925f4367c83c77f66a89e5ca7229c288d2d19ad5f36d1ca0070/coverage-7.15.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb3c2aacea411cc7e1d27712490c11108e2de1d39019ae32915493a59a8b9ed", size = 258587, upload-time = "2026-08-06T13:49:28.692Z" }, + { url = "https://files.pythonhosted.org/packages/45/8c/fa34044f71b7cc4ecb6da9c2408770959b0591fa9b5fb6fb6bca38f94298/coverage-7.15.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9447978a92f405d301123cfd39ff49895490efb769a758fe2734c7f631bf8ce", size = 260785, upload-time = "2026-08-06T13:49:30.472Z" }, + { url = "https://files.pythonhosted.org/packages/4f/54/d5727ce36b4524a7394ab9f5f1df378e1f23affcdab01037dc8655185cc7/coverage-7.15.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:050467a7983b8e2fe7dd41a78bb30c3e7f8c0b8cafda14b1c46f8b5e3cf2dd3c", size = 254545, upload-time = "2026-08-06T13:49:32.271Z" }, + { url = "https://files.pythonhosted.org/packages/dc/e6/6e3783e576719590194bdffb6dd6d85490801785b7c331e35a245d8cb8b5/coverage-7.15.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:d003b7a5708ddad5c206c79607a6b92abb6fc13c57d99d8a4468cc03a2941ced", size = 256682, upload-time = "2026-08-06T13:49:34.089Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f2/bacdbde18b69ed2de424fcf64d9fb0a4913753d4f0eca8bae9daad69f4bd/coverage-7.15.4-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:c38efe30fd74e5c19e9433f11fb1f5dc9c6522770971b7c6145bbaa413dc8800", size = 254560, upload-time = "2026-08-06T13:49:36.052Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a3/1fb927196e3477c1b48831169ab58ba08f451ba87ae311ff1de68b26a616/coverage-7.15.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:1f4f826d70f772ab8b0c052329580d7fe8b8abd191e4ce0c8f81aec6614665d3", size = 258792, upload-time = "2026-08-06T13:49:38.01Z" }, + { url = "https://files.pythonhosted.org/packages/41/58/30d4c149c69053de0edfe325614c1d28d508f62b1783e0e4a234d2e49136/coverage-7.15.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:4a4bf917c9953f57c957be31c1cd504e3bd2f34d4a352b9d391a3025336f6768", size = 253968, upload-time = "2026-08-06T13:49:39.934Z" }, + { url = "https://files.pythonhosted.org/packages/89/e4/77f639371b918aad30dda4051f95404b43578f7f2e2f87ba73e02ed1ff37/coverage-7.15.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:1c9bf40ebef178a45192c75c4964760bb261b0e6ad725da5fc4c93f674f19753", size = 255893, upload-time = "2026-08-06T13:49:41.825Z" }, + { url = "https://files.pythonhosted.org/packages/5c/62/13be29b3ddab35f14c87967a4820a05106d2a3eccb4fa4ff550bf30b75e0/coverage-7.15.4-cp315-cp315-win32.whl", hash = "sha256:43619d04c3671792d2c4706ae8bf45e265dc87bbd4078189ef8b847ea1e74be2", size = 224768, upload-time = "2026-08-06T13:49:44.08Z" }, + { url = "https://files.pythonhosted.org/packages/a1/70/af0c6be0f964af6954f6b74bc109b0dbca02824696d2520fb17fe1ab06e3/coverage-7.15.4-cp315-cp315-win_amd64.whl", hash = "sha256:be619439dbcd31a2eab10b32de9fff62c26ed4bab69dc32b8363fdaaa0882809", size = 225242, upload-time = "2026-08-06T13:49:45.899Z" }, + { url = "https://files.pythonhosted.org/packages/4f/2d/f3bd3aab899fc9efc18b53133ee68f5f98574ef480649b23e12962226387/coverage-7.15.4-cp315-cp315-win_arm64.whl", hash = "sha256:def597967dafc2e8d97c9097ea453c464e0bb8ed38f193a43070f10dc623bb6d", size = 224674, upload-time = "2026-08-06T13:49:48.322Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ca/f69251cd63eabc6438321aea22148754cce758a26bde07dd490e3fe7cfc5/coverage-7.15.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c7dbc748ac8a1e3e59a2b28bea47675e6e778081dbbf081bde0d75def2fcbe1d", size = 223333, upload-time = "2026-08-06T13:49:50.293Z" }, + { url = "https://files.pythonhosted.org/packages/a7/a7/037b53b2885b0d8447064432491a4d5a1014cd9f97a594d53acd0c04541a/coverage-7.15.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:2413074a5ecbb61a01a7888fc72db0ca324d13588c5b38bc0dd8564cdcdfea26", size = 223630, upload-time = "2026-08-06T13:49:52.637Z" }, + { url = "https://files.pythonhosted.org/packages/80/4f/152b8a4779ae90da11bb24f7467df8a59f0be48a5c52acb856325ca48289/coverage-7.15.4-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4e6f6f632b7b2f714bf7a1346e8f97b650ee71f3c298aaad42a2ab60f0f07645", size = 264489, upload-time = "2026-08-06T13:49:54.52Z" }, + { url = "https://files.pythonhosted.org/packages/10/2d/84b4b9e0e1dd6528a51920ff7031f35b789382e467a28ec6a5a578cb8812/coverage-7.15.4-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8df457da2249d3c75ca2e5e835d59c725abfe92d27fdff6cd99eed85b51d5e9a", size = 267567, upload-time = "2026-08-06T13:49:56.721Z" }, + { url = "https://files.pythonhosted.org/packages/53/fc/ba01cc25299f9f8a2c8b02d3b28c53f3543d9fbfbe4e74fa2760b48f163e/coverage-7.15.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:050f66a08805acb5b8a23c6d4a517b1ecf82c08e81ed0e4bd727df065e5c6624", size = 270123, upload-time = "2026-08-06T13:49:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/cf/d0/db2647cbf40b14f8c308f94ff7bf89c06d564e59f396906edf50086ec788/coverage-7.15.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1587fb771d1ccceef708fdde1e5af8c7ed24b486b61d13a321acb7d8145390aa", size = 271107, upload-time = "2026-08-06T13:50:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4d2d17924552c458bb4f77dd631f0e3bc92fbbdf2d2d916cd4b33bbfd5b1/coverage-7.15.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8b4f1c3a69ca580f3fbd6b2046915f536d7f586874f25c1bb23add2a3c88d50f", size = 264955, upload-time = "2026-08-06T13:50:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/ee/de/dc010c7a3691f396d93bbc26bfcafa1c2a3a351cd520470f15faf5795bd5/coverage-7.15.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:ffb58d7eff5b7f6ecc6fa21d6288ab7f968a212cb67d682c269c09b9eba3b66f", size = 267949, upload-time = "2026-08-06T13:50:05.557Z" }, + { url = "https://files.pythonhosted.org/packages/78/ea/dc96a11375e83c045c2f7c61fb6918277cfe9401db7c0f7b1d111a84b2e5/coverage-7.15.4-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:d9df165544774574ee004b953023d1bebada1894a80b1052a43d798b0f676e67", size = 264421, upload-time = "2026-08-06T13:50:07.612Z" }, + { url = "https://files.pythonhosted.org/packages/c8/86/b77131a0f9503ce461cd577076147d7a9040f0c5dda772686f729e2cc9cb/coverage-7.15.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:f9de0a24a4079b53e523b5c5e2c5945ec251ab486652659955187cf255a259bc", size = 269121, upload-time = "2026-08-06T13:50:09.58Z" }, + { url = "https://files.pythonhosted.org/packages/24/24/944bc35007862955e7ebf05754e645419dcf5d7526c52735cfa2715e8ebf/coverage-7.15.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:150089274bdc9f940628552cb92844e0223c987f1902ab8efe9f45a2ec758d88", size = 264565, upload-time = "2026-08-06T13:50:11.722Z" }, + { url = "https://files.pythonhosted.org/packages/c7/cc/a3bb9f93e7e740659163e2ea584f8196ddcd2c456a5dbe15f6c50105fec1/coverage-7.15.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:a58a94fed5da6997d258e8f7668c1e195fbd04a691d781b7558f1e468f9e68bc", size = 266522, upload-time = "2026-08-06T13:50:13.786Z" }, + { url = "https://files.pythonhosted.org/packages/49/dd/e0e40f3560d878d888c580698ff5ad1179f5e1c3ac949684ef66b41a3817/coverage-7.15.4-cp315-cp315t-win32.whl", hash = "sha256:ebd5a6d8466ff30836572f3ba2cae8a5e8f85029b1c6d5e2ed338dc472a5166a", size = 225068, upload-time = "2026-08-06T13:50:15.825Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/37732ea80eebc30e976e4cdab15c190bc42d96959a42e38ddf6f8c60468f/coverage-7.15.4-cp315-cp315t-win_amd64.whl", hash = "sha256:288bde2a2d7ab6b6c2d7252fcde8b524387f2d970bdba9658fc6f8bbcaef0f9b", size = 225895, upload-time = "2026-08-06T13:50:17.928Z" }, + { url = "https://files.pythonhosted.org/packages/c6/08/1e00f7923eaaba45fb3d51dd794125fc766304b1df264f3a9c6557bfb30e/coverage-7.15.4-cp315-cp315t-win_arm64.whl", hash = "sha256:68be5e1de60ff13c9095bbec0e5a7fa45b33b101752215b91345ea1f61c4a278", size = 225213, upload-time = "2026-08-06T13:50:19.981Z" }, + { url = "https://files.pythonhosted.org/packages/b4/d9/e70c286c979378f061d8266e279b686ab0b0b688e1fe0af864684f23a77d/coverage-7.15.4-py3-none-any.whl", hash = "sha256:964730a1e9de9c0cf11be6a1a3c79ce419c34882842abd256086ba4698705e84", size = 214332, upload-time = "2026-08-06T13:50:22.192Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "orgmetra-hris-kernel" +version = "0.4.0" +source = { directory = "../../packages/hris-kernel" } + +[package.metadata] +requires-dist = [ + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "orgmetra-job-analysis-api" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "orgmetra-hris-kernel" }, + { name = "orgmetra-keyverse-adapter" }, +] + +[package.optional-dependencies] +test = [ + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "orgmetra-hris-kernel", directory = "../../packages/hris-kernel" }, + { name = "orgmetra-keyverse-adapter", directory = "../../packages/keyverse-adapter" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "orgmetra-keyverse-adapter" +version = "0.1.0" +source = { directory = "../../packages/keyverse-adapter" } + +[package.metadata] +requires-dist = [ + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] diff --git a/services/people-api/pyproject.toml b/services/people-api/pyproject.toml index 3f228e11c..785f188ce 100644 --- a/services/people-api/pyproject.toml +++ b/services/people-api/pyproject.toml @@ -7,14 +7,21 @@ name = "orgmetra-people-api" version = "0.1.0" description = "Purpose-bound customer API boundary for authoritative Orgmetra HR records." readme = "README.md" -requires-python = ">=3.11" +requires-python = ">=3.12" license = { text = "Apache-2.0" } authors = [{ name = "ContextualWisdomLab" }] dependencies = [ - "orgmetra-hris-kernel==0.1.0", + "orgmetra-hris-kernel==0.4.0", "orgmetra-keyverse-adapter==0.1.0", ] +[project.optional-dependencies] +test = ["pytest>=8.3", "pytest-cov>=5.0"] + +[tool.uv.sources] +orgmetra-hris-kernel = { path = "../../packages/hris-kernel" } +orgmetra-keyverse-adapter = { path = "../../packages/keyverse-adapter" } + [tool.setuptools] package-dir = {"" = "src"} diff --git a/services/people-api/uv.lock b/services/people-api/uv.lock new file mode 100644 index 000000000..cac614b5b --- /dev/null +++ b/services/people-api/uv.lock @@ -0,0 +1,225 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/c3/4f2195f512fb172aa425a8803a874b2baa9ba7f80ff7b6080998761fc701/coverage-7.15.4.tar.gz", hash = "sha256:0548198fff07ccf4faf469520bce1c2eceb1ce3e62891921138dec10907f9d00", size = 936952, upload-time = "2026-08-06T13:50:24.442Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/48/bc8d4ba7b37551a767bd863f15b3f80182b271c2f55975356f5f7dbe94c2/coverage-7.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4fedd1f7f428f9fe83b1ead5e7cc87a43427be31aadafbac3ac0636dc7abb22", size = 222543, upload-time = "2026-08-06T13:47:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/20/dd/88d6f83f1fffc974a3691a34a97951c5b12df7512a6782c5963883cbc058/coverage-7.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37e2f0cdf58e2e1fed4e4d5a8f8786ae2f7eb80b478016876667dc4a01d60a97", size = 222905, upload-time = "2026-08-06T13:47:38.927Z" }, + { url = "https://files.pythonhosted.org/packages/bd/5c/54ee0d4748585bb0acab9891cd8d92f2d3593165b4e59fc9de113bfb3140/coverage-7.15.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fb55d0e70bb15f2e81477613627286581414693d74ac7963c93a790dd453ca9d", size = 254407, upload-time = "2026-08-06T13:47:40.488Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3f/f0642a372f494bd0d7dad3b497083b910194a5f1c88be2c94fef707c3b59/coverage-7.15.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:899b9da30f3c6c336566e3707495bb23e8302d39d862f01fa78c48b99b9437e2", size = 257145, upload-time = "2026-08-06T13:47:41.931Z" }, + { url = "https://files.pythonhosted.org/packages/71/17/8b46d0ed68251016002ec972c8fc0119961a765d0984cafb8bf317c43758/coverage-7.15.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d15715e8c46552827e5e4f30a35575a2dbcad14454cf3284c54483946bd16931", size = 258257, upload-time = "2026-08-06T13:47:43.527Z" }, + { url = "https://files.pythonhosted.org/packages/30/b8/8498a0e72d0adbe15477dd07463d2b3bb2c9f6a4815e8589e50939e2c3ae/coverage-7.15.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:002a438859f7b430bc99afeaf01a6d187dad1d0dc907b64cdeffc632a5db8fd8", size = 260517, upload-time = "2026-08-06T13:47:45.121Z" }, + { url = "https://files.pythonhosted.org/packages/41/e1/7dce19c3bdb1e3dd63e769508216500edad81bd5f69a26d724e32aceaf78/coverage-7.15.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e4193a04b518f7968f3099755f5509ee7cccc6dc2b92a6b14841934d22e222c9", size = 254785, upload-time = "2026-08-06T13:47:46.541Z" }, + { url = "https://files.pythonhosted.org/packages/dd/b1/e1494703c675a2561723cd9b89f45c9168782c31280c611b1f767851e57c/coverage-7.15.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e98dcc55d572b38e69d117da7e8e8efb8500f1f5eaf81ecd460a63220790b839", size = 256176, upload-time = "2026-08-06T13:47:48.155Z" }, + { url = "https://files.pythonhosted.org/packages/73/76/a5629d270fb638a43a4b10466f51e2f49d532c1aa4da2913cbbb150bbe0a/coverage-7.15.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:af6c538498ce66c10d3fd541c2a8d5b03da5850355add34e6cba564210cb9e72", size = 254321, upload-time = "2026-08-06T13:47:49.757Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/9c44447218435d5766b911534f9d798144a5560f85e9a54ebe5f3f5d19f9/coverage-7.15.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1d10025d96ea89fc2f73714dbc4cbd433fe012c1ac9e23f895d7728b238b6e52", size = 258390, upload-time = "2026-08-06T13:47:51.248Z" }, + { url = "https://files.pythonhosted.org/packages/de/36/c1e127616fb3fa18a9ff71e76c417f2fd7424332a4870015ac224ef4c039/coverage-7.15.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d802e1947603162ded419bff83ac7489820355d2b856dfb09206574e3a37ac0c", size = 253894, upload-time = "2026-08-06T13:47:52.816Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b9/fdb92c8ae7a8bb9b850cc253b7b3b9c8526f68130002048b5671cd510d09/coverage-7.15.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2de40895718f91951b86712b4c5b694acaf9a0a49be13874896f599a1eed3f4", size = 255763, upload-time = "2026-08-06T13:47:54.296Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/a7d51b2587c7bdb76e71b0896d2565bf7d60436b5122fc83e511adb1f7cd/coverage-7.15.4-cp312-cp312-win32.whl", hash = "sha256:5c3431b2161279b7db5c2a1aa58ae02e5cb8c3c42d93a5094be3f5537bd5b11b", size = 224597, upload-time = "2026-08-06T13:47:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/49/b9/5c5f80cc55f5acaaca6dee677626bfcec8c87204a7809b438b08e84f4571/coverage-7.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:6befeab5fb2b51c958ca4ac6c5d141a1e8240f4f76e46350f1911963deda49cd", size = 225135, upload-time = "2026-08-06T13:47:57.52Z" }, + { url = "https://files.pythonhosted.org/packages/47/e4/2a4561f89ff6bf7c925c287d0f2cce8bdf139c3a33735c87e3203401cf94/coverage-7.15.4-cp312-cp312-win_arm64.whl", hash = "sha256:67bc345491ab55b837277d76f5775d057e8c7f1ac44d890d8c2c82adde258c6f", size = 224515, upload-time = "2026-08-06T13:47:58.977Z" }, + { url = "https://files.pythonhosted.org/packages/f1/84/651a9310859673aaa3b3203f1aa1641ca60fcf2494683e1c9474c7172780/coverage-7.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c705b28feb2775dc82a25f1d473a370bc37ff93f5177f4e29ce2425f560f6921", size = 222565, upload-time = "2026-08-06T13:48:00.796Z" }, + { url = "https://files.pythonhosted.org/packages/82/f9/4dcf700137e8af550670f4d74d1b63828ce93e1e2b05e5f10710eb2ea987/coverage-7.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ff205ab5e3ecc670f6a4dd19d9cbf12ede53dd41cfc1e15716ec961ea6d314e", size = 222936, upload-time = "2026-08-06T13:48:02.391Z" }, + { url = "https://files.pythonhosted.org/packages/07/4a/612ff1e780b3fbfd637486f542f84adc5503873d8b5d279dec1ffeef9414/coverage-7.15.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5172326e861a38b48b48befca15e0f477a26b283337a33a739c8fed229934e36", size = 253926, upload-time = "2026-08-06T13:48:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/b0/04/d1cff1c2ead4708a6a79c01d3736b6a25bd38a36678398f72a8dd33dfad9/coverage-7.15.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:12b59c90084e3234fb11184886bf4a40f4f16a8c8f867be2e087b81f8e8868d4", size = 256523, upload-time = "2026-08-06T13:48:05.996Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/d34e13fb4b293cbdb9665838cf5522077b8ad14ef947550631a4bced36a5/coverage-7.15.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349062d66f00b40fa2c1c222438bad25fabf755631b5d82937fe985c8008615c", size = 257759, upload-time = "2026-08-06T13:48:08.036Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e7/2c5fe7636fdb0732fe0f09f308a5b066864078b7fc61f6678e8478554f2e/coverage-7.15.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4256ced708e598e05209bc1a8ab4074e04a51dba4c62fb45926a229af675ace7", size = 259890, upload-time = "2026-08-06T13:48:09.834Z" }, + { url = "https://files.pythonhosted.org/packages/92/28/9689f0858dfff59c2ea688938ab9fa2925631235df67126a42b6c5c70ae1/coverage-7.15.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d80f974b20782d9612c8b4c9beeca867074c7cf4079d1419843fa25a26428b25", size = 254121, upload-time = "2026-08-06T13:48:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/785077c230c157243eb5aa9a26c3be260ecd02001bead54a3cada3df8e03/coverage-7.15.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e179f19bfe1d31f8eeeaa12990194d761c4f62f0759661000bca6cd8729f40b", size = 255891, upload-time = "2026-08-06T13:48:13.209Z" }, + { url = "https://files.pythonhosted.org/packages/d4/90/e20371b17b40f912f21305c2db2f30efa3de306f7320fc916804872c85a4/coverage-7.15.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8bc16bb47b7679670eceff71d78bfb7d6e5b143f6c2cd117487ec7c75e0d4b78", size = 253859, upload-time = "2026-08-06T13:48:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/05/49/25371987ee459a5f67c0427fb75c74f9358e65f2c71fe75bf41c1b6c5fcb/coverage-7.15.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1cd685005cd2c4200adfc14cf39a603b9320efab3f18a8f7f156d20c9cc3345f", size = 258011, upload-time = "2026-08-06T13:48:16.464Z" }, + { url = "https://files.pythonhosted.org/packages/30/6e/32e67467f6154bf4f1c4f63b05acc5097cba4237d45bbeeea446b52e8ac1/coverage-7.15.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:337399ad2c93b3acd2a937627dae8b3e86b66707cd3d3e856347999aadf1ef8d", size = 253676, upload-time = "2026-08-06T13:48:18.493Z" }, + { url = "https://files.pythonhosted.org/packages/03/c1/8b24192e89286399765155251f99ee9f070a9d637109018ac23d99b99f6f/coverage-7.15.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:96e257121228ec5cd2bb919276e94ac11074471bc37d68dbae0e8308cce15fff", size = 255453, upload-time = "2026-08-06T13:48:20.057Z" }, + { url = "https://files.pythonhosted.org/packages/16/6f/8b41ebdf67c87854e17c035336a90f1cfbad0c14c2a584301be6ff148718/coverage-7.15.4-cp313-cp313-win32.whl", hash = "sha256:c65a9e0dfc6143491879da4e13b5e30f8be192055de508d737fb14601edbd22c", size = 224605, upload-time = "2026-08-06T13:48:21.655Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e2/2946c7f0b42b152ecb21ff1bdad72e3d301e790c0c487e4a86e8c9f69347/coverage-7.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:2ff8f5e9b8f7a94f0c11c45631eee103dbcb7d63274edd12c56efe1be690b3b4", size = 225148, upload-time = "2026-08-06T13:48:23.376Z" }, + { url = "https://files.pythonhosted.org/packages/9e/83/3f4a69957f48ae7a0aba76c34743f88963d607b19e03f3f8e66f91cae0f9/coverage-7.15.4-cp313-cp313-win_arm64.whl", hash = "sha256:6e0a8a5083b096487d6cfced94cdd514d8f5db6f113610fb36c0620edb1028cf", size = 224536, upload-time = "2026-08-06T13:48:25.117Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ac/748cf29eeb2d6be34a3176ce26a4f49e38085ee08e8935f05f6f26ed7e0f/coverage-7.15.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:770e9325ab5ea6d56f77e59b29ecfe0ac20b57a82a601876f90494a4dda0386f", size = 222608, upload-time = "2026-08-06T13:48:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/0b/02/1abbf5c984677b0aa439cdacaccbf38d248939d8ef8fe1cc7a50d73edb77/coverage-7.15.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d12b33a3a50a1676b7784dc8d00a0c6d66a9f2add4b85a041c19b6a7e53ef23c", size = 222940, upload-time = "2026-08-06T13:48:28.432Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e1/ff8f9f53d9fcf586125b55d0b1f04ec1c14955fee41e83d5814bee141bb5/coverage-7.15.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5669c8378ebde86f5def7a25d29586631b58acc27ffde04399f678f3dfc6e082", size = 253985, upload-time = "2026-08-06T13:48:29.995Z" }, + { url = "https://files.pythonhosted.org/packages/a1/26/595759762e514e81be1d7d01ed03444303bcd152226a6529998d253f9201/coverage-7.15.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ff97a14362eef486483ed44042ca2027ea257df6ff768e62358ee0c9776925ac", size = 256492, upload-time = "2026-08-06T13:48:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/b79aabac54d482be23b5fcdd4f4662bff24a78edc4ee29201726929936d5/coverage-7.15.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a325e815318638aed1655d9c06e6d7c2d3d46c09231ce988070428a8762d734", size = 257837, upload-time = "2026-08-06T13:48:33.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/0f/bf7f297885a5bf6fd71e5782404e0ff059ca09e8711ceb3a08544abde45a/coverage-7.15.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:474223409d88eb20d2d6a0d37ea60e8647a65a90cc008dc1f0410af5f64f1e0d", size = 260152, upload-time = "2026-08-06T13:48:34.75Z" }, + { url = "https://files.pythonhosted.org/packages/fd/f1/296744e854ff8368542343457414380465e9ceefb9192342feb9d3bc461d/coverage-7.15.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f2f62ae3cd189dd2e13aece758c57b3eecbd27be070dbd4cbd10936049e5dbf", size = 253978, upload-time = "2026-08-06T13:48:36.434Z" }, + { url = "https://files.pythonhosted.org/packages/55/b0/bbdb2e9057493e66220a2e149ca2d301ba0e3a58a83bd6b90de9826d16f3/coverage-7.15.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:39ece820e29e0a2ba34b3ecb3be83c27e997eed8926f2ba6fe7ce7a0bda5843b", size = 255846, upload-time = "2026-08-06T13:48:38.317Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/38015b2b6d21258713bd17e76b59d033b191efb5703589cffd037dfbca20/coverage-7.15.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f21b56dcace11dfe013014201f577dcd592b2a9b72182d930361b47cf6f73f25", size = 253808, upload-time = "2026-08-06T13:48:39.993Z" }, + { url = "https://files.pythonhosted.org/packages/0b/64/0d515c1e60ee6fbfd1a0e79c07cd87d388a233b7adc37758735677203808/coverage-7.15.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:93a3a0b662abcc10c73a47cbc72cd60f63618d6989fb2d1286e50eacd974f303", size = 258081, upload-time = "2026-08-06T13:48:41.971Z" }, + { url = "https://files.pythonhosted.org/packages/91/71/04d9e7a3642146c6351338aef4ef85ab11dbbb54744c13245caba1aad1c0/coverage-7.15.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:141fae2cabf5569b782c10afc4c850ce10f618c13f8db54765cba99cc839da1f", size = 253624, upload-time = "2026-08-06T13:48:43.731Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a7/6c28b74c81ebff66987b0e2522ba5cffa3e90b0c33cb6a2eb264d4ee8cf1/coverage-7.15.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:81294c7e6ab30c5f74c0353b11b2fd6320e72d9bee6ac73b357caa8b916323a5", size = 255280, upload-time = "2026-08-06T13:48:45.58Z" }, + { url = "https://files.pythonhosted.org/packages/52/af/bc19996a7014b98d7bbb0f0939453c67074af65784a3aa16a789a07381fa/coverage-7.15.4-cp314-cp314-win32.whl", hash = "sha256:7bbd7d6418e0dab31a206af5203bd43ae36edb8e7fba1940b055d3e9249290d7", size = 224768, upload-time = "2026-08-06T13:48:47.525Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/219484e476d6e101ba0a444852579e05f5b75c37c611a42ed1190f73ef62/coverage-7.15.4-cp314-cp314-win_amd64.whl", hash = "sha256:f0204ed122758782970526057093f448051a39db9d810d4e344bb87a3546f425", size = 225259, upload-time = "2026-08-06T13:48:49.513Z" }, + { url = "https://files.pythonhosted.org/packages/b7/66/fa77daf4e383e5f776dac62c2409b6af81910ae6fe326bd5170dba74cc63/coverage-7.15.4-cp314-cp314-win_arm64.whl", hash = "sha256:9e71e7bc71c686a123347ae47a0de33a175e797a85bb57b791492adf4eec8ed8", size = 224684, upload-time = "2026-08-06T13:48:51.235Z" }, + { url = "https://files.pythonhosted.org/packages/58/5b/f03bf0ce362bbf3f785fa5219620d00778d4ac6fc9e407734828e9c672f6/coverage-7.15.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7c922735321eef3f87c280a3d39afff6b646723a2880b862cda4ac7a093b8aa8", size = 223338, upload-time = "2026-08-06T13:48:52.896Z" }, + { url = "https://files.pythonhosted.org/packages/0f/76/e77d0ae22501831cc9f92193e8a957a5caa1dd177f90a6d1d9b106242d92/coverage-7.15.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f41c17c4668a655ce96d090d8d5ffdc24ef64b5a02f9753884d08483e8a4a41a", size = 223609, upload-time = "2026-08-06T13:48:54.688Z" }, + { url = "https://files.pythonhosted.org/packages/82/1a/b1f089da8d38ac612fa2dd6dc7f4a1a7657d12f3e261d2996edd3a838d0b/coverage-7.15.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:46822e9b6ff1c6a72b518c162c44a8f45a61a1d609c51084bf5b16c023c5037b", size = 264970, upload-time = "2026-08-06T13:48:56.403Z" }, + { url = "https://files.pythonhosted.org/packages/bf/31/e66d98d6e9c7fcc88470f1e234eaf6b1950dc0dfbf797f7282c1c861da24/coverage-7.15.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d6f4955b73b5445271379a59e3792b0d978f42d4a01e0cf7a67d9c33a3bb0a5", size = 267088, upload-time = "2026-08-06T13:48:58.41Z" }, + { url = "https://files.pythonhosted.org/packages/59/a1/ae94eb2c541add426378408379f233591e069040b1e2cdb33df9498a0682/coverage-7.15.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3fc9e047706fb4a9abb54f719d3aa643e80e5bb3818182c40aee01ac0f0247ba", size = 269508, upload-time = "2026-08-06T13:49:00.42Z" }, + { url = "https://files.pythonhosted.org/packages/9c/c7/88a10694a1c6a213569766aba9f25847b28155d4ac731b13226db216356d/coverage-7.15.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05e491d4f3165d62d4f5c8fd48dfeabf2ae8f42cbbd484319af33ea851b78982", size = 270629, upload-time = "2026-08-06T13:49:02.234Z" }, + { url = "https://files.pythonhosted.org/packages/b3/34/d8b8232e5e55169933b59aabcef2fedfa4b9d8897361bb80fcbda146505f/coverage-7.15.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:226c66e80ec0598d3b9b4874123df167ccca342aca8714f77cac6829688ee09c", size = 264043, upload-time = "2026-08-06T13:49:04.102Z" }, + { url = "https://files.pythonhosted.org/packages/7e/35/58b009dbf8c471c7224716478b9fed4a7e1af15320e1ed41660978504663/coverage-7.15.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac41cc14bebda0dbfb0628036b7f75706935c95bcc07fefe9a0f93614aa60a57", size = 266963, upload-time = "2026-08-06T13:49:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/62/aa/57fbda1b42c892968273c56b6ee9dc0f1310850859230a507bc7873b1f65/coverage-7.15.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8af623e5cd92080acddd02b38f2f406a2c3a0893c38950b211890361448fbf26", size = 264569, upload-time = "2026-08-06T13:49:07.706Z" }, + { url = "https://files.pythonhosted.org/packages/98/8a/360e6e7f24d477b7e889703af0afa878d15b6d4d8d2a822b2835c169a879/coverage-7.15.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07545711d4f0f32852a18f18ad11f76f0109909d09e78b9008b4cfc67e829429", size = 268299, upload-time = "2026-08-06T13:49:09.587Z" }, + { url = "https://files.pythonhosted.org/packages/4e/89/6f701261aee21b6b5fa8f7872229406dc917e125069448292223bf213606/coverage-7.15.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a0865421cfdc53654b342d515e5a233187590882d20b95752150e53f65460017", size = 263413, upload-time = "2026-08-06T13:49:11.604Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0f/6f04036edc260ed425af83e834f627fad48941ce97b50bfe6edd8b6fa623/coverage-7.15.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:460115e32ee40566476db5048f9bec1e842c127ad8e6f8be745aad3ac9cbc839", size = 265725, upload-time = "2026-08-06T13:49:13.38Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ce/d19b5d4d5c49a7bfb925fd74310fee7d28bc99520ac3367ccbc54e662518/coverage-7.15.4-cp314-cp314t-win32.whl", hash = "sha256:cbde877ef9dd7baf272b9bfef2b8a25edd45d9170fc326951dd20eb480335e85", size = 225079, upload-time = "2026-08-06T13:49:15.265Z" }, + { url = "https://files.pythonhosted.org/packages/26/bb/7aa1b3b173faee0679037ca950bbbe1247273656697994d8d13f80f8d4b4/coverage-7.15.4-cp314-cp314t-win_amd64.whl", hash = "sha256:3da9e92d1c551fd7563833e9ade686efb0c4b7363ab7681a94283958c950bf5e", size = 225911, upload-time = "2026-08-06T13:49:17.279Z" }, + { url = "https://files.pythonhosted.org/packages/81/1c/4ea9e47426d80038d9222db3c4534cb6021a74b237d3ff97ffd33b6600dd/coverage-7.15.4-cp314-cp314t-win_arm64.whl", hash = "sha256:3a54f5a0d85050c73a38f6793090ee83974531e67fe5e57a1da9bee11398aa5e", size = 225219, upload-time = "2026-08-06T13:49:19.293Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c4/dc5d2ac8f9142e7ec7de66e7bf0591db29d78955a040bd915870d9c0e657/coverage-7.15.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:2c9872e4d9dc5d3cf616bf4b382f5a00359305a5be666a3dd0b5cdb4e49597f9", size = 222604, upload-time = "2026-08-06T13:49:21.279Z" }, + { url = "https://files.pythonhosted.org/packages/70/39/33e63df81fe2ee100897451841c821467635923e58e37c6bd4b46dd8106c/coverage-7.15.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:e101dbb4b9b72f0cddd8cdc8c9c5b47f456766f5e0ac82dbfb75e5c55409b78a", size = 222944, upload-time = "2026-08-06T13:49:23.187Z" }, + { url = "https://files.pythonhosted.org/packages/99/1f/ef3ffb5557febc75a0d97aa459d0266d7d741110265121cc6d8539343d44/coverage-7.15.4-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7d1abebdb047729e852b9c77a00497dfbeb11eb3a117e037d7dbc3ac8e5f5c54", size = 254050, upload-time = "2026-08-06T13:49:25.008Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f5/1f0f6f77698c3601ca0ae7431e34b24c62ca2f06fecb23b73ed1f651d2be/coverage-7.15.4-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d28a4a899354d0ea6214cc59b4fa19eefbce1b9ff1688ab579acf49e894bd3fb", size = 256967, upload-time = "2026-08-06T13:49:26.896Z" }, + { url = "https://files.pythonhosted.org/packages/03/7a/2ed9bed79925f4367c83c77f66a89e5ca7229c288d2d19ad5f36d1ca0070/coverage-7.15.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb3c2aacea411cc7e1d27712490c11108e2de1d39019ae32915493a59a8b9ed", size = 258587, upload-time = "2026-08-06T13:49:28.692Z" }, + { url = "https://files.pythonhosted.org/packages/45/8c/fa34044f71b7cc4ecb6da9c2408770959b0591fa9b5fb6fb6bca38f94298/coverage-7.15.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9447978a92f405d301123cfd39ff49895490efb769a758fe2734c7f631bf8ce", size = 260785, upload-time = "2026-08-06T13:49:30.472Z" }, + { url = "https://files.pythonhosted.org/packages/4f/54/d5727ce36b4524a7394ab9f5f1df378e1f23affcdab01037dc8655185cc7/coverage-7.15.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:050467a7983b8e2fe7dd41a78bb30c3e7f8c0b8cafda14b1c46f8b5e3cf2dd3c", size = 254545, upload-time = "2026-08-06T13:49:32.271Z" }, + { url = "https://files.pythonhosted.org/packages/dc/e6/6e3783e576719590194bdffb6dd6d85490801785b7c331e35a245d8cb8b5/coverage-7.15.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:d003b7a5708ddad5c206c79607a6b92abb6fc13c57d99d8a4468cc03a2941ced", size = 256682, upload-time = "2026-08-06T13:49:34.089Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f2/bacdbde18b69ed2de424fcf64d9fb0a4913753d4f0eca8bae9daad69f4bd/coverage-7.15.4-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:c38efe30fd74e5c19e9433f11fb1f5dc9c6522770971b7c6145bbaa413dc8800", size = 254560, upload-time = "2026-08-06T13:49:36.052Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a3/1fb927196e3477c1b48831169ab58ba08f451ba87ae311ff1de68b26a616/coverage-7.15.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:1f4f826d70f772ab8b0c052329580d7fe8b8abd191e4ce0c8f81aec6614665d3", size = 258792, upload-time = "2026-08-06T13:49:38.01Z" }, + { url = "https://files.pythonhosted.org/packages/41/58/30d4c149c69053de0edfe325614c1d28d508f62b1783e0e4a234d2e49136/coverage-7.15.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:4a4bf917c9953f57c957be31c1cd504e3bd2f34d4a352b9d391a3025336f6768", size = 253968, upload-time = "2026-08-06T13:49:39.934Z" }, + { url = "https://files.pythonhosted.org/packages/89/e4/77f639371b918aad30dda4051f95404b43578f7f2e2f87ba73e02ed1ff37/coverage-7.15.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:1c9bf40ebef178a45192c75c4964760bb261b0e6ad725da5fc4c93f674f19753", size = 255893, upload-time = "2026-08-06T13:49:41.825Z" }, + { url = "https://files.pythonhosted.org/packages/5c/62/13be29b3ddab35f14c87967a4820a05106d2a3eccb4fa4ff550bf30b75e0/coverage-7.15.4-cp315-cp315-win32.whl", hash = "sha256:43619d04c3671792d2c4706ae8bf45e265dc87bbd4078189ef8b847ea1e74be2", size = 224768, upload-time = "2026-08-06T13:49:44.08Z" }, + { url = "https://files.pythonhosted.org/packages/a1/70/af0c6be0f964af6954f6b74bc109b0dbca02824696d2520fb17fe1ab06e3/coverage-7.15.4-cp315-cp315-win_amd64.whl", hash = "sha256:be619439dbcd31a2eab10b32de9fff62c26ed4bab69dc32b8363fdaaa0882809", size = 225242, upload-time = "2026-08-06T13:49:45.899Z" }, + { url = "https://files.pythonhosted.org/packages/4f/2d/f3bd3aab899fc9efc18b53133ee68f5f98574ef480649b23e12962226387/coverage-7.15.4-cp315-cp315-win_arm64.whl", hash = "sha256:def597967dafc2e8d97c9097ea453c464e0bb8ed38f193a43070f10dc623bb6d", size = 224674, upload-time = "2026-08-06T13:49:48.322Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ca/f69251cd63eabc6438321aea22148754cce758a26bde07dd490e3fe7cfc5/coverage-7.15.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c7dbc748ac8a1e3e59a2b28bea47675e6e778081dbbf081bde0d75def2fcbe1d", size = 223333, upload-time = "2026-08-06T13:49:50.293Z" }, + { url = "https://files.pythonhosted.org/packages/a7/a7/037b53b2885b0d8447064432491a4d5a1014cd9f97a594d53acd0c04541a/coverage-7.15.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:2413074a5ecbb61a01a7888fc72db0ca324d13588c5b38bc0dd8564cdcdfea26", size = 223630, upload-time = "2026-08-06T13:49:52.637Z" }, + { url = "https://files.pythonhosted.org/packages/80/4f/152b8a4779ae90da11bb24f7467df8a59f0be48a5c52acb856325ca48289/coverage-7.15.4-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4e6f6f632b7b2f714bf7a1346e8f97b650ee71f3c298aaad42a2ab60f0f07645", size = 264489, upload-time = "2026-08-06T13:49:54.52Z" }, + { url = "https://files.pythonhosted.org/packages/10/2d/84b4b9e0e1dd6528a51920ff7031f35b789382e467a28ec6a5a578cb8812/coverage-7.15.4-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8df457da2249d3c75ca2e5e835d59c725abfe92d27fdff6cd99eed85b51d5e9a", size = 267567, upload-time = "2026-08-06T13:49:56.721Z" }, + { url = "https://files.pythonhosted.org/packages/53/fc/ba01cc25299f9f8a2c8b02d3b28c53f3543d9fbfbe4e74fa2760b48f163e/coverage-7.15.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:050f66a08805acb5b8a23c6d4a517b1ecf82c08e81ed0e4bd727df065e5c6624", size = 270123, upload-time = "2026-08-06T13:49:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/cf/d0/db2647cbf40b14f8c308f94ff7bf89c06d564e59f396906edf50086ec788/coverage-7.15.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1587fb771d1ccceef708fdde1e5af8c7ed24b486b61d13a321acb7d8145390aa", size = 271107, upload-time = "2026-08-06T13:50:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4d2d17924552c458bb4f77dd631f0e3bc92fbbdf2d2d916cd4b33bbfd5b1/coverage-7.15.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8b4f1c3a69ca580f3fbd6b2046915f536d7f586874f25c1bb23add2a3c88d50f", size = 264955, upload-time = "2026-08-06T13:50:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/ee/de/dc010c7a3691f396d93bbc26bfcafa1c2a3a351cd520470f15faf5795bd5/coverage-7.15.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:ffb58d7eff5b7f6ecc6fa21d6288ab7f968a212cb67d682c269c09b9eba3b66f", size = 267949, upload-time = "2026-08-06T13:50:05.557Z" }, + { url = "https://files.pythonhosted.org/packages/78/ea/dc96a11375e83c045c2f7c61fb6918277cfe9401db7c0f7b1d111a84b2e5/coverage-7.15.4-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:d9df165544774574ee004b953023d1bebada1894a80b1052a43d798b0f676e67", size = 264421, upload-time = "2026-08-06T13:50:07.612Z" }, + { url = "https://files.pythonhosted.org/packages/c8/86/b77131a0f9503ce461cd577076147d7a9040f0c5dda772686f729e2cc9cb/coverage-7.15.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:f9de0a24a4079b53e523b5c5e2c5945ec251ab486652659955187cf255a259bc", size = 269121, upload-time = "2026-08-06T13:50:09.58Z" }, + { url = "https://files.pythonhosted.org/packages/24/24/944bc35007862955e7ebf05754e645419dcf5d7526c52735cfa2715e8ebf/coverage-7.15.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:150089274bdc9f940628552cb92844e0223c987f1902ab8efe9f45a2ec758d88", size = 264565, upload-time = "2026-08-06T13:50:11.722Z" }, + { url = "https://files.pythonhosted.org/packages/c7/cc/a3bb9f93e7e740659163e2ea584f8196ddcd2c456a5dbe15f6c50105fec1/coverage-7.15.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:a58a94fed5da6997d258e8f7668c1e195fbd04a691d781b7558f1e468f9e68bc", size = 266522, upload-time = "2026-08-06T13:50:13.786Z" }, + { url = "https://files.pythonhosted.org/packages/49/dd/e0e40f3560d878d888c580698ff5ad1179f5e1c3ac949684ef66b41a3817/coverage-7.15.4-cp315-cp315t-win32.whl", hash = "sha256:ebd5a6d8466ff30836572f3ba2cae8a5e8f85029b1c6d5e2ed338dc472a5166a", size = 225068, upload-time = "2026-08-06T13:50:15.825Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/37732ea80eebc30e976e4cdab15c190bc42d96959a42e38ddf6f8c60468f/coverage-7.15.4-cp315-cp315t-win_amd64.whl", hash = "sha256:288bde2a2d7ab6b6c2d7252fcde8b524387f2d970bdba9658fc6f8bbcaef0f9b", size = 225895, upload-time = "2026-08-06T13:50:17.928Z" }, + { url = "https://files.pythonhosted.org/packages/c6/08/1e00f7923eaaba45fb3d51dd794125fc766304b1df264f3a9c6557bfb30e/coverage-7.15.4-cp315-cp315t-win_arm64.whl", hash = "sha256:68be5e1de60ff13c9095bbec0e5a7fa45b33b101752215b91345ea1f61c4a278", size = 225213, upload-time = "2026-08-06T13:50:19.981Z" }, + { url = "https://files.pythonhosted.org/packages/b4/d9/e70c286c979378f061d8266e279b686ab0b0b688e1fe0af864684f23a77d/coverage-7.15.4-py3-none-any.whl", hash = "sha256:964730a1e9de9c0cf11be6a1a3c79ce419c34882842abd256086ba4698705e84", size = 214332, upload-time = "2026-08-06T13:50:22.192Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "orgmetra-hris-kernel" +version = "0.4.0" +source = { directory = "../../packages/hris-kernel" } + +[package.metadata] +requires-dist = [ + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "orgmetra-keyverse-adapter" +version = "0.1.0" +source = { directory = "../../packages/keyverse-adapter" } + +[package.metadata] +requires-dist = [ + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "orgmetra-people-api" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "orgmetra-hris-kernel" }, + { name = "orgmetra-keyverse-adapter" }, +] + +[package.optional-dependencies] +test = [ + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "orgmetra-hris-kernel", directory = "../../packages/hris-kernel" }, + { name = "orgmetra-keyverse-adapter", directory = "../../packages/keyverse-adapter" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0" }, +] +provides-extras = ["test"] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] diff --git a/tests/e2e/hr-workspace-core-model.spec.mjs b/tests/e2e/hr-workspace-core-model.spec.mjs new file mode 100644 index 000000000..2ea5d1514 --- /dev/null +++ b/tests/e2e/hr-workspace-core-model.spec.mjs @@ -0,0 +1,27 @@ +import { expect, test } from '@playwright/test'; + +const workspacePath = '/apps/hr-workspace/index.html'; + +test('employee profile keeps Job, Position, and Assignment as distinct HRIS concepts', async ({ page }) => { + await page.goto(workspacePath); + await page.locator('[data-view-link="employee-profile"]').first().click(); + + const conceptGrid = page.locator('#view-employee-profile .concept-grid'); + await expect(conceptGrid.locator('.concept-card')).toHaveCount(5); + + const jobCard = conceptGrid.locator('.concept-card', { hasText: 'job_record' }); + const positionCard = conceptGrid.locator('.concept-card', { hasText: 'position_record' }); + const assignmentCard = conceptGrid.locator('.concept-card', { hasText: 'assignment_record' }); + + await expect(jobCard).toHaveCount(1); + await expect(positionCard).toHaveCount(1); + await expect(assignmentCard).toHaveCount(1); + await expect(jobCard.locator('strong')).toHaveText('job_record'); + await expect(positionCard.locator('strong')).toHaveText('position_record'); + await expect(assignmentCard.locator('strong')).toHaveText('assignment_record'); + + await page.locator('#locale-toggle').click(); + await expect(jobCard).toContainText('직무'); + await expect(positionCard).toContainText('직위'); + await expect(assignmentCard).toContainText('배정'); +}); diff --git a/tests/e2e/hr-workspace.spec.mjs b/tests/e2e/hr-workspace.spec.mjs new file mode 100644 index 000000000..6f99cbe0e --- /dev/null +++ b/tests/e2e/hr-workspace.spec.mjs @@ -0,0 +1,274 @@ +import { expect, test } from '@playwright/test'; + +const workspacePath = '/apps/hr-workspace/index.html'; + +async function injectProtectedReadConfig(page) { + await page.addInitScript(() => { + const baseUrl = window.location.origin; + const getAuthorization = () => 'Bearer e2e-host-token'; + window.__ORGMETRA_JOB_ANALYSIS__ = { + baseUrl, + tenantRecordId: 'tenant-e2e', + analysisRecordId: 'analysis-e2e', + purposeCode: 'job_analysis_read', + getAuthorization, + }; + window.__ORGMETRA_PEOPLE__ = { + baseUrl, + tenantRecordId: 'tenant-e2e', + personRecordId: 'person-e2e', + effectiveOn: '2026-08-21', + purposeCode: 'people_read', + requestedFields: ['display_name', 'employment_status_code'], + getAuthorization, + }; + }); +} + +test('human-review workspace states remain keyboard-accessible and localized', async ({ page }) => { + await page.goto(workspacePath); + + await expect(page.getByRole('heading', { name: 'HR Home' })).toBeVisible(); + const localeToggle = page.locator('#locale-toggle'); + await expect(localeToggle).toHaveText('한국어'); + await expect(localeToggle).toHaveAccessibleName('Change language to 한국어'); + await page.locator('[data-view-link="employee-profile"]').first().click(); + await expect(page.getByRole('heading', { name: 'Employee Profile' })).toBeVisible(); + + await page.locator('#access-purpose').selectOption('recruiting'); + await page.locator('[data-action="view-personal-details"]').click(); + await expect(page.locator('#permission-panel')).toBeVisible(); + await expect(page.locator('#details-panel')).toBeHidden(); + + await page.locator('#access-purpose').selectOption('hr_operations'); + await page.locator('[data-action="view-personal-details"]').click(); + await expect(page.locator('#details-panel')).toBeVisible(); + await expect(page.locator('#permission-panel')).toBeHidden(); + + await localeToggle.click(); + await expect(page.locator('html')).toHaveAttribute('lang', 'ko'); + await expect(page.getByRole('heading', { name: '직원 프로필' })).toBeVisible(); + await expect(localeToggle).toHaveText('English'); + await expect(localeToggle).toHaveAccessibleName('언어를 English로 변경'); + + await page.locator('[data-action="correct-history"]').click(); + const confirmationDialog = page.locator('#confirmation-dialog'); + await expect(confirmationDialog).toBeVisible(); + await page.locator('#confirm-correction').click(); + await expect(page.locator('#confirmation-reason')).toBeFocused(); + await page.locator('#confirmation-reason').fill('Review the effective-date evidence before correction.'); + await page.locator('#confirm-correction').click(); + await expect(page.locator('#confirmation-status')).toBeVisible(); + await expect(page.locator('#confirmation-status')).toContainText('정정 초안을 확인'); + + await page.getByRole('button', { name: '취소' }).click(); + await expect(confirmationDialog).toBeHidden(); + await page.locator('[data-action="correct-history"]').click(); + await expect(confirmationDialog).toBeVisible(); + await expect(page.locator('#confirmation-status')).toBeHidden(); + await expect(page.locator('#confirmation-reason')).toHaveValue(''); +}); + +test('unconfigured protected reads stay neutral and explain the host next action', async ({ page }) => { + await page.goto(workspacePath); + + await page.locator('[data-view-link="employee-profile"]').first().click(); + const peopleStatus = page.locator('#people-api-status'); + await expect(peopleStatus).toHaveAttribute('data-state', 'not-configured'); + await expect(peopleStatus).toContainText('host must provide a People API URL and authorization provider'); + await page.getByRole('button', { name: 'Load worker record' }).click(); + await expect(peopleStatus).toHaveAttribute('data-state', 'not-configured'); + await expect(page.locator('#people-api-result')).toBeHidden(); + + await page.locator('[data-view-link="job-analysis"]').first().click(); + const jobAnalysisStatus = page.locator('#job-analysis-status'); + await expect(jobAnalysisStatus).toHaveAttribute('data-state', 'not-configured'); + await expect(jobAnalysisStatus).toContainText('host must provide an API base URL and authorization provider'); + await page.getByRole('button', { name: 'Load snapshot' }).click(); + await expect(jobAnalysisStatus).toHaveAttribute('data-state', 'not-configured'); + await expect(page.locator('#job-analysis-result')).toBeHidden(); +}); + +test('connected read views use host authorization and render API evidence', async ({ page }) => { + await injectProtectedReadConfig(page); + const requests = []; + await page.route('**/v1/tenants/**/people/**', async (route) => { + const request = route.request(); + requests.push({ + kind: 'people', + url: request.url(), + authorization: (await request.headers()).authorization, + }); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ fields: { display_name: 'E2E authorized worker', employment_status_code: 'active' } }), + }); + }); + await page.route('**/v1/tenants/**/job-analysis-snapshots/**', async (route) => { + const request = route.request(); + requests.push({ + kind: 'job-analysis', + url: request.url(), + authorization: (await request.headers()).authorization, + purpose: (await request.headers())['x-purpose-code'], + }); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + analysis_record_id: 'analysis-e2e', + status_code: 'analysis_validated', + effective_from: '2026-08-01', + recorded_at: '2026-08-18T05:00:00Z', + content_digest_sha256: 'a'.repeat(64), + tasks: [{ task_id: 'task-e2e' }], + ksao_requirements: [{ ksao_id: 'ksao-e2e' }], + }), + }); + }); + + await page.goto(workspacePath); + await page.locator('[data-view-link="employee-profile"]').first().click(); + await page.getByRole('button', { name: 'Load worker record' }).click(); + await expect(page.locator('#people-api-status')).toHaveAttribute('data-state', 'loaded'); + await expect(page.locator('#people-api-display-name')).toHaveText('E2E authorized worker'); + await expect(page.locator('#people-api-employment-status')).toHaveText('active'); + + await page.locator('[data-view-link="job-analysis"]').first().click(); + await page.getByRole('button', { name: 'Load snapshot' }).click(); + await expect(page.locator('#job-analysis-status')).toHaveAttribute('data-state', 'loaded'); + await expect(page.locator('#job-analysis-task-count')).toHaveText('1'); + await expect(page.locator('#job-analysis-ksao-count')).toHaveText('1'); + + const peopleRequest = requests.find((request) => request.kind === 'people'); + const peopleUrl = new URL(peopleRequest.url); + expect(peopleRequest.authorization).toBe('Bearer e2e-host-token'); + expect(peopleUrl.searchParams.get('effective_on')).toBe('2026-08-21'); + expect(peopleUrl.searchParams.get('purpose')).toBe('people_read'); + expect(peopleUrl.searchParams.get('fields')).toBe('display_name,employment_status_code'); + + const jobAnalysisRequest = requests.find((request) => request.kind === 'job-analysis'); + expect(jobAnalysisRequest.authorization).toBe('Bearer e2e-host-token'); + expect(jobAnalysisRequest.purpose).toBe('job_analysis_read'); +}); + +test('denied protected reads show an actionable error without local fallback', async ({ page }) => { + await injectProtectedReadConfig(page); + await page.route('**/v1/tenants/**/people/**', async (route) => { + await route.fulfill({ + status: 403, + contentType: 'application/json', + body: JSON.stringify({ error_code: 'access_denied', message: 'denied' }), + }); + }); + + await page.goto(workspacePath); + await page.locator('[data-view-link="employee-profile"]').first().click(); + await page.getByRole('button', { name: 'Load worker record' }).click(); + await expect(page.locator('#people-api-status')).toHaveAttribute('data-state', 'error'); + await expect(page.locator('#people-api-status')).toContainText('denied'); + await expect(page.locator('#people-api-result')).toBeHidden(); + await expect(page.locator('#people-api-display-name')).toHaveText('unknown'); +}); + +test('a denied People reread removes previously authorized fields before the response settles', async ({ page }) => { + await injectProtectedReadConfig(page); + let requestCount = 0; + await page.route('**/v1/tenants/**/people/**', async (route) => { + requestCount += 1; + if (requestCount === 1) { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ fields: { display_name: 'Previously authorized worker', employment_status_code: 'active' } }), + }); + return; + } + await new Promise((resolve) => setTimeout(resolve, 150)); + await route.fulfill({ + status: 403, + contentType: 'application/json', + body: JSON.stringify({ error_code: 'access_denied', message: 'denied' }), + }); + }); + + await page.goto(workspacePath); + await page.locator('[data-view-link="employee-profile"]').first().click(); + const loadButton = page.getByRole('button', { name: 'Load worker record' }); + await loadButton.click(); + await expect(page.locator('#people-api-result')).toBeVisible(); + await expect(page.locator('#people-api-display-name')).toHaveText('Previously authorized worker'); + + await loadButton.click(); + await expect(page.locator('#people-api-result')).toBeHidden(); + await expect(page.locator('#people-api-display-name')).toHaveText('unknown'); + await expect(page.locator('#people-api-status')).toHaveAttribute('data-state', 'error'); + await expect(page.locator('#people-api-result')).toBeHidden(); +}); + +test('only the latest People read may render when responses complete out of order', async ({ page }) => { + await injectProtectedReadConfig(page); + let requestCount = 0; + let markFirstRequestSeen; + const firstRequestSeen = new Promise((resolve) => { + markFirstRequestSeen = resolve; + }); + await page.route('**/v1/tenants/**/people/**', async (route) => { + requestCount += 1; + if (requestCount === 1) { + markFirstRequestSeen(); + await new Promise((resolve) => setTimeout(resolve, 200)); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ fields: { display_name: 'Stale worker', employment_status_code: 'inactive' } }), + }); + return; + } + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ fields: { display_name: 'Latest worker', employment_status_code: 'active' } }), + }); + }); + + await page.goto(workspacePath); + await page.locator('[data-view-link="employee-profile"]').first().click(); + const loadButton = page.getByRole('button', { name: 'Load worker record' }); + await loadButton.click(); + await firstRequestSeen; + await page.locator('#people-api-person').fill('person-latest'); + await loadButton.click(); + + await expect(page.locator('#people-api-status')).toHaveAttribute('data-state', 'loaded'); + await expect(page.locator('#people-api-display-name')).toHaveText('Latest worker'); + await expect(page.locator('#people-api-employment-status')).toHaveText('active'); + await page.waitForTimeout(250); + await expect(page.locator('#people-api-display-name')).toHaveText('Latest worker'); + await expect(page.locator('#people-api-employment-status')).toHaveText('active'); +}); + +test('keyboard users can bypass repeated workspace navigation', async ({ page }) => { + await page.goto(workspacePath); + + await page.keyboard.press('Tab'); + const skipLink = page.getByRole('link', { name: 'Skip to main content' }); + await expect(skipLink).toBeFocused(); + await expect(skipLink).toBeVisible(); + + await skipLink.press('Enter'); + await expect(page.locator('#main-content')).toBeFocused(); +}); + +test('the bypass control follows the active workspace locale', async ({ page }) => { + await page.goto(workspacePath); + + const skipLink = page.locator('a.skip-link[href="#main-content"]'); + await expect(skipLink).toHaveAccessibleName('Skip to main content'); + await page.locator('#locale-toggle').click(); + await expect(page.locator('html')).toHaveAttribute('lang', 'ko'); + await expect(skipLink.locator('[lang="ko"]')).toBeVisible(); + await expect(skipLink.locator('[lang="en"]')).toBeHidden(); + await expect(skipLink).toHaveAccessibleName('본문으로 건너뛰기'); +}); diff --git a/tests/foundation-contract.test.mjs b/tests/foundation-contract.test.mjs index 72b18466f..911f03b81 100644 --- a/tests/foundation-contract.test.mjs +++ b/tests/foundation-contract.test.mjs @@ -266,6 +266,15 @@ test('local links validate files and ignore anchors, web, and mail links', () => } }); +test('ADR index keeps provenance outside canonical status cells', () => { + const indexText = readFileSync(new URL('../docs/adr/README.md', import.meta.url), 'utf8'); + assert.doesNotMatch( + indexText, + /\|\s*(?:Proposed|Accepted|Superseded|Rejected)\s+on\s+[^|]+\|/, + 'ADR status cells must remain canonical; branch provenance belongs in a separate column' + ); +}); + test('ADR index reports missing files and status mismatch', () => { const root = temporaryDirectory(); try { diff --git a/tests/hr-workspace.test.mjs b/tests/hr-workspace.test.mjs new file mode 100644 index 000000000..4ebad403d --- /dev/null +++ b/tests/hr-workspace.test.mjs @@ -0,0 +1,138 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; +import { + fetchJobAnalysisSnapshot, + fetchPeopleRecord, + isPurposeAuthorized, + jobAnalysisSnapshotUrl, + nextLocale, + peopleRecordUrl, +} from '../apps/hr-workspace/app.js'; + +const html = readFileSync(new URL('../apps/hr-workspace/index.html', import.meta.url), 'utf8'); +const css = readFileSync(new URL('../apps/hr-workspace/styles.css', import.meta.url), 'utf8'); +const app = readFileSync(new URL('../apps/hr-workspace/app.js', import.meta.url), 'utf8'); +const story = readFileSync(new URL('../apps/hr-workspace/workspace.stories.js', import.meta.url), 'utf8'); +const storybookConfig = readFileSync(new URL('../.storybook/main.js', import.meta.url), 'utf8'); +const storybookPreview = readFileSync(new URL('../.storybook/preview.js', import.meta.url), 'utf8'); + +test('workspace exposes the Figma role slice and existing design tokens', () => { + assert.match(html, /packages\/design-tokens\/tokens\.css/); + assert.match(html, /data-node-id="1:10"/); + assert.match(html, /data-node-id="1:28"/); + assert.match(html, /data-view-link="hr-home"/); + assert.match(html, /data-view-link="employee-profile"/); + assert.match(html, /data-view-link="job-analysis"/); + assert.match(html, /id="people-api-form"/); + assert.match(css, /var\(--orgmetra-action-review\)/); + assert.match(css, /var\(--orgmetra-focus-ring\)/); +}); + +test('workspace includes keyboard-accessible review and high-impact states', () => { + assert.match(html, /id="evidence-dialog"/); + assert.match(html, /id="confirmation-dialog"/); + assert.match(html, /role="alert"/); + assert.match(html, /role="status"/); + assert.match(html, /aria-label="Close"/); + assert.match(html, /required rows="3"/); + assert.match(html, /Exact assignment allocation values/); +}); + +test('locale-sensitive icon controls translate their accessible names', () => { + assert.match( + html, + /id="locale-toggle"[^>]*data-i18n-aria-label="changeLanguage"/, + 'language toggle needs a locale-bound accessible name', + ); + assert.equal( + (html.match(/data-i18n-aria-label="close"/g) ?? []).length, + 2, + 'both icon-only dialog close buttons need locale-bound accessible names', + ); + assert.match(app, /querySelectorAll\('\[data-i18n-aria-label\]'\)/); + assert.match(app, /dictionary\[element\.dataset\.i18nAriaLabel\]/); +}); + +test('Storybook exposes tokenized workspace states without claiming API connectivity', () => { + assert.match(storybookConfig, /@storybook\/web-components-vite/); + assert.match(storybookPreview, /design-tokens\/tokens\.css/); + for (const storyName of [ + 'ActionButtons', + 'FieldStates', + 'PermissionDenied', + 'EvidenceDrawer', + 'HighRiskConfirmation', + 'AssignmentSplit', + 'PeopleNotConnected', + 'JobAnalysisNotConnected', + ]) { + assert.match(story, new RegExp(`export const ${storyName}`)); + } + assert.match(story, /orgmetra-action-request-evidence/); + assert.match(story, /Exact assignment allocation values/); + assert.match(story, /aria-invalid="true"/); + assert.match(story, /data-figma-node-id="2:2"/); + assert.match(story, /Connect the host before loading protected data/); + assert.match(story, /No local fallback is used/); +}); + +test('purpose and locale transitions preserve the trust boundary', () => { + assert.equal(isPurposeAuthorized('hr_operations'), true); + assert.equal(isPurposeAuthorized('recruiting'), false); + assert.equal(nextLocale('en'), 'ko'); + assert.equal(nextLocale('ko'), 'en'); + assert.match(app, /no API mutation was sent/); + assert.doesNotMatch(html, /password|passkey_value|private_key/i); +}); + +test('Job Analysis uses a host authorization provider without persisting bearer material', async () => { + const config = { + baseUrl: 'https://job-analysis.example.test/', + tenantRecordId: 'tenant/alpha', + analysisRecordId: 'analysis-1', + purposeCode: 'job_analysis_read', + getAuthorization: async () => 'Bearer host-provided-token', + }; + assert.equal( + jobAnalysisSnapshotUrl(config), + 'https://job-analysis.example.test/v1/tenants/tenant%2Falpha/job-analysis-snapshots/analysis-1', + ); + let request; + const snapshot = await fetchJobAnalysisSnapshot(config, async (url, options) => { + request = { url, options }; + return { ok: true, status: 200, json: async () => ({ analysis_record_id: 'analysis-1' }) }; + }); + assert.deepEqual(snapshot, { analysis_record_id: 'analysis-1' }); + assert.equal(request.url, jobAnalysisSnapshotUrl(config)); + assert.equal(request.options.credentials, 'omit'); + assert.equal(request.options.headers.Authorization, 'Bearer host-provided-token'); + assert.equal(request.options.headers['X-Purpose-Code'], 'job_analysis_read'); + assert.doesNotMatch(html, /localStorage|sessionStorage|authorization.*input/i); +}); + +test('People API uses host authorization and an explicit no-storage read boundary', async () => { + const config = { + baseUrl: 'https://people.example.test/', + tenantRecordId: 'tenant/alpha', + personRecordId: 'person-1', + effectiveOn: '2026-08-21', + purposeCode: 'people_read', + requestedFields: ['display_name', 'employment_status_code'], + getAuthorization: async () => 'Bearer host-provided-token', + }; + assert.equal( + peopleRecordUrl(config), + 'https://people.example.test/v1/tenants/tenant%2Falpha/people/person-1?effective_on=2026-08-21&purpose=people_read&fields=display_name%2Cemployment_status_code', + ); + let request; + const record = await fetchPeopleRecord(config, async (url, options) => { + request = { url, options }; + return { ok: true, status: 200, json: async () => ({ fields: { display_name: 'Authorized worker', employment_status_code: 'active' } }) }; + }); + assert.deepEqual(record.fields, { display_name: 'Authorized worker', employment_status_code: 'active' }); + assert.equal(request.url, peopleRecordUrl(config)); + assert.equal(request.options.credentials, 'omit'); + assert.equal(request.options.headers.Authorization, 'Bearer host-provided-token'); + assert.doesNotMatch(html, /localStorage|sessionStorage|authorization.*input/i); +}); diff --git a/tests/validate_repository.py b/tests/validate_repository.py index fe0a329ff..6ad2cf89b 100644 --- a/tests/validate_repository.py +++ b/tests/validate_repository.py @@ -23,8 +23,17 @@ "NOTICE", "manifest.json", "package.json", + "package-lock.json", + ".storybook/main.js", + ".storybook/preview.js", + "apps/hr-workspace/index.html", + "apps/hr-workspace/styles.css", + "apps/hr-workspace/app.js", + "apps/hr-workspace/workspace.stories.js", ".github/workflows/foundation-ci.yml", ".github/workflows/job-analysis-api-quality.yml", + ".github/workflows/hr-workspace-browser-e2e.yml", + "playwright.config.mjs", "docs/PRD.md", "docs/TRD.md", "docs/USER_STORIES.md", @@ -40,6 +49,7 @@ "docs/TEST_STRATEGY.md", "docs/OPERABILITY.md", "docs/TRACEABILITY.md", + "docs/product-technical-gap-baseline.md", "docs/adr/README.md", "docs/adr/0001-orgmetra-authoritative-hris-record.md", "docs/adr/0002-federated-cwl-integration-boundaries.md", @@ -55,6 +65,7 @@ "docs/adr/0012-governed-migration-handoff.md", "docs/adr/0013-governed-requisition-review-packet.md", "docs/adr/0014-job-analysis-snapshot-persistence.md", + "docs/adr/0026-product-technical-gap-baseline.md", "docs/doctoring/REFERENCES.md", "docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md", "docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md", @@ -78,6 +89,8 @@ "scripts/foundation-contract.mjs", "tests/dispatcher-inventory.test.mjs", "tests/foundation-contract.test.mjs", + "tests/hr-workspace.test.mjs", + "tests/e2e/hr-workspace.spec.mjs", "tests/openapi-contract.test.mjs", "tests/test_bitemporal_postgres.sh", "tests/test_tenant_isolation_postgres.sh", @@ -139,7 +152,7 @@ def _expected_manifest_document() -> dict[str, Any]: return { "package": "orgmetra-foundation-pack", "version": "0.1.0", - "generated_for_branch": "feat/audit-outbox-envelope", + "generated_for_branch": "develop", "files": files, } @@ -153,10 +166,10 @@ def _manifest_entries() -> dict[str, dict[str, Any]]: if not isinstance(manifest, dict) or not isinstance(manifest.get("files"), list): _fail("manifest.json must contain a files array") - if manifest.get("generated_for_branch") != "feat/audit-outbox-envelope": + if manifest.get("generated_for_branch") != "develop": _fail( "manifest generated_for_branch must identify the active generation branch " - "feat/audit-outbox-envelope" + "develop" ) entries: dict[str, dict[str, Any]] = {} @@ -597,6 +610,8 @@ def _validate_openapi_contract() -> None: def _validate_markdown() -> None: """Reject explicit unfinished-work markers with exact path/line and malformed fences.""" for path in ROOT.rglob("*.md"): + if {"node_modules", "storybook-static"}.intersection(path.parts): + continue text = path.read_text(encoding="utf-8") for line_number, line in enumerate(text.splitlines(), start=1): if UNFINISHED_MARKER_LINE_PATTERN.fullmatch(line):