-
Notifications
You must be signed in to change notification settings - Fork 0
feat: record explicit assignment category #163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
seonghobae
wants to merge
95
commits into
develop
Choose a base branch
from
feat/explicit-assignment-category
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
95 commits
Select commit
Hold shift + click to select a range
269c911
test: require explicit assignment category contract
seonghobae 5160e55
feat(hris): carry explicit assignment category
seonghobae e794bb0
feat(hris): enforce explicit primary assignment invariant
seonghobae 67f5fca
feat(people): require assignment category on writes
seonghobae 230736a
chore: apply assignment category integration repair
seonghobae 2d05737
test(assignments): reject new legacy assignment categories
seonghobae c1cef84
fix(assignments): reserve legacy category for migrated history
seonghobae 4863294
chore(assignments): retire temporary source-fix workflow
seonghobae a2df987
ci(assignments): prove category persistence boundary
seonghobae 87023a1
feat(assignments): require category at HTTP boundary
seonghobae 7f7c2e8
test(assignments): require explicit HTTP category
seonghobae 9fc12cf
feat(assignments): persist category through PostgreSQL adapter
seonghobae 248948a
test(assignments): require category in OpenAPI contract
seonghobae 8e3afd7
feat(assignments): publish category in OpenAPI
seonghobae b411285
docs(assignments): record explicit category decision
seonghobae e6bd170
docs(assignments): index assignment category ADR
seonghobae a434a45
docs(assignments): align data model with category contract
seonghobae 5bebae5
docs(assignments): publish API category semantics
seonghobae 5984c60
docs(assignments): align ERD category invariant
seonghobae a48cb62
docs(assignments): trace explicit category contract
seonghobae 2bce218
fix(foundation): inventory assignment migration contract
seonghobae 601152b
fix(foundation): mirror assignment execution inventory
seonghobae e9f7918
chore(foundation): emit exact assignment manifest repair data
seonghobae 274bcea
chore(assignment): finalize manifest and changelog evidence
seonghobae c9f275f
test(openapi): bound schema fixtures by exact indentation
seonghobae 2529fd9
chore(assignment): retrigger exact-head finalization
seonghobae 09a2dd5
chore(assignment): seal final evidence
github-actions[bot] e8886c5
test(assignment): reject non-string category writes
seonghobae edee1ec
test(red): preserve legacy assignment system-time closure
seonghobae 0530b1c
fix(assignments): preserve legacy system-time closure
seonghobae 10daff6
chore(manifest): reseal assignment category migration
seonghobae 03959f6
docs(adr): keep assignment category decision proposed
seonghobae 02c034b
docs(data): clarify legacy assignment closure guard
seonghobae 1694229
chore(manifest): reseal assignment category documentation
seonghobae ec18afc
test(assignments): cover classified-to-legacy rejection
seonghobae 9912840
test: reject assignment category runtime spoofing
seonghobae c49e999
fix: require exact assignment category strings
seonghobae 7487b56
fix: reject assignment category runtime spoofing
seonghobae de7f24e
fix: backfill assignment category without rewriting history
seonghobae 300bbdb
chore: reseal assignment category migration
seonghobae 9b41472
docs(adr): keep assignment category decision proposed
seonghobae b86fe90
chore(manifest): reseal ADR status correction
seonghobae 4fe2889
fix(manifest): restore unchanged gitignore digest
seonghobae 2f5c555
test: reject legacy sentinel at assignment write boundary
seonghobae 8ccb112
test: preserve historical assignment validation semantics
seonghobae 046e3fc
test: align People assignment fixture with explicit category
seonghobae a7a2ae5
fix: reseal assignment category PostgreSQL evidence
seonghobae c67a54e
fix: repair unrelated manifest digest copy
seonghobae 6213830
test: require validated assignment category constraint
seonghobae f63fc96
fix(db): validate assignment category check after migration
seonghobae e9dacb7
chore: reseal assignment category migration evidence
seonghobae 0da0c15
chore: preserve manifest trailing newline
seonghobae a2c220a
fix(ci): pin assignment category runner image
seonghobae 628ffd4
test: expose assignment aggregate serialization race
seonghobae d4cc84c
fix: serialize assignment writes by employment aggregate
seonghobae 22c93ef
fix: avoid redundant employment row lock
seonghobae e23f126
test: keep assignment fixture aligned with category row shape
seonghobae 47372c4
test: prove assignment category migration rolls back atomically
seonghobae 2a0ee95
fix: make assignment category migration atomic
seonghobae 2dc6ef7
chore: reseal assignment category recovery evidence
seonghobae 73e2cf7
fix: restore unrelated manifest digest
seonghobae 9a2e3fd
fix(assignment): enforce category guard before history guard
seonghobae b2cdabf
chore: reseal assignment migration integrity
seonghobae 473f574
test(people): reject forged persisted assignment categories
seonghobae 2172ce7
fix(people): reject forged persisted assignment categories
seonghobae aecb978
test: pin assignment category provenance inventory
seonghobae b8b60d8
test: execute assignment category provenance regression
seonghobae 0726253
fix: seal assignment category governance artifacts
seonghobae 60e3461
fix: align Python provenance inventory
seonghobae 06bd520
fix: seal assignment category provenance
seonghobae 84ca6d2
fix: restore unrelated manifest digest
seonghobae fb51af2
test(people): reject unknown persisted assignment categories
seonghobae cb3b20b
fix(people): fail closed on unknown persisted assignment category
seonghobae a92e94a
docs(assignment): bound category correction claim to shipped behavior
seonghobae 680d7b1
chore(foundation): reseal assignment category ADR provenance
seonghobae 28dd172
test(hris): reject forged assignment allocation ratios
seonghobae f720870
fix(hris): reject executable Decimal allocation subtypes
seonghobae 68acd1c
test(hris): reject forged seat allocation ratios
seonghobae f3d044a
fix(hris): guard seat allocation numeric runtime type
seonghobae ed05f82
test(people): reject forged command allocation ratio
seonghobae 8b4e2cd
fix(people): require exact Decimal allocation command
seonghobae e27c585
merge(develop): adopt queue-saturation workflow relief
seonghobae 67154ff
test(hris): require explicit assignment category construction
seonghobae fcfaf73
test(hris): mark historical assignment fixtures explicitly
seonghobae a80569d
test(hris): classify position-capacity assignment fixtures
seonghobae c1a93d0
test(hris): classify historical lifecycle fixture explicitly
seonghobae 5d2e340
test(hris): classify workforce boundary fixtures explicitly
seonghobae c17ed82
test(hris): classify workforce composition fixtures explicitly
seonghobae d168196
test(hris): classify portfolio fixtures explicitly
seonghobae 3f57b78
fix(hris): require explicit assignment category facts
seonghobae 6801445
fix(ci): cover all assignment category governed artifacts
seonghobae 1f079ee
chore(provenance): reseal assignment category workflow
seonghobae 1a3e146
style(hris): format explicit assignment fixtures
seonghobae 5d4133b
merge(develop): adopt restored documentation contract checks
seonghobae 0d61f5b
test(assignment): cover rejected portfolio categories
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| name: Assignment Category Quality | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - bootstrap | ||
| - develop | ||
| - main | ||
| paths: | ||
| - "database/migrations/0017_assignment_category_code.sql" | ||
| - "docs/adr/0015-explicit-assignment-category.md" | ||
| - "docs/API_CONTRACT.md" | ||
| - "docs/DATA_MODEL.md" | ||
| - "docs/ERD.md" | ||
| - "docs/TRACEABILITY.md" | ||
| - "manifest.json" | ||
| - "packages/hris-kernel/**" | ||
| - "schemas/openapi.yaml" | ||
| - "services/people-api/**" | ||
| - "tests/assignment-category-provenance.test.mjs" | ||
| - "tests/openapi-contract.test.mjs" | ||
| - "tests/test_assignment_category_postgres.sh" | ||
| - "tests/validate_repository.py" | ||
| - ".github/workflows/assignment-category-quality.yml" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: assignment-category-quality-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| postgres: | ||
| name: Explicit assignment category persistence contract | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 10 | ||
| services: | ||
| postgres: | ||
| image: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20 | ||
| env: | ||
| POSTGRES_USER: orgmetra | ||
| POSTGRES_PASSWORD: orgmetra | ||
| POSTGRES_DB: orgmetra | ||
| ports: | ||
| - 5432:5432 | ||
| options: >- | ||
| --health-cmd "pg_isready -U orgmetra -d orgmetra" | ||
| --health-interval 5s | ||
| --health-timeout 5s | ||
| --health-retries 10 | ||
| env: | ||
| DATABASE_URL: postgresql://orgmetra:orgmetra@localhost:5432/orgmetra | ||
| 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: Prove assignment category provenance inventory | ||
| run: node --test tests/assignment-category-provenance.test.mjs | ||
| - name: Prove migration compatibility and new-write invariants | ||
| run: bash tests/test_assignment_category_postgres.sh | ||
| - name: Require clean checkout | ||
| run: | | ||
| git diff --exit-code | ||
| test -z "$(git status --porcelain)" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| -- Record assignment role classification as authoritative HRIS truth. | ||
| -- Historical rows are preserved explicitly; no allocation/order heuristic is allowed. | ||
| -- The constant default materializes the historical sentinel for pre-contract rows | ||
| -- without issuing an UPDATE that would violate the existing bitemporal history | ||
| -- guard. Dropping the default immediately keeps every post-contract write explicit. | ||
| -- legacy_unspecified is migration provenance only. The table constraint preserves | ||
| -- that historical sentinel so system-time closure remains possible, while the | ||
| -- write guard rejects introduction of the sentinel on a new row or by changing | ||
| -- an already classified row back to legacy state. | ||
|
|
||
| BEGIN; | ||
|
|
||
| SET LOCAL search_path = public, pg_catalog; | ||
|
|
||
| ALTER TABLE public.assignment_record | ||
| ADD COLUMN assignment_category_code text NOT NULL DEFAULT 'legacy_unspecified'; | ||
|
|
||
| ALTER TABLE public.assignment_record | ||
| ALTER COLUMN assignment_category_code DROP DEFAULT; | ||
|
|
||
| ALTER TABLE public.assignment_record | ||
| ADD CONSTRAINT assignment_record_category_code_check | ||
| CHECK (assignment_category_code IN ('legacy_unspecified', 'primary', 'concurrent_secondary')) NOT VALID; | ||
|
|
||
| -- Add the constraint without the strongest validation-time table lock, then | ||
| -- prove every migrated historical row conforms before the migration completes. | ||
| ALTER TABLE public.assignment_record | ||
| VALIDATE CONSTRAINT assignment_record_category_code_check; | ||
|
|
||
| CREATE FUNCTION public.enforce_assignment_category_write() | ||
| RETURNS trigger | ||
| LANGUAGE plpgsql | ||
| SET search_path = pg_catalog, public | ||
| AS $$ | ||
| BEGIN | ||
| IF NEW.assignment_category_code = 'legacy_unspecified' THEN | ||
| IF TG_OP = 'INSERT' THEN | ||
| RAISE EXCEPTION 'assignment_record_category_code_check: legacy_unspecified is migration provenance only' | ||
| USING ERRCODE = 'check_violation', | ||
| CONSTRAINT = 'assignment_record_category_code_check', | ||
| TABLE = 'assignment_record', | ||
| SCHEMA = 'public'; | ||
| ELSIF OLD.assignment_category_code IS DISTINCT FROM 'legacy_unspecified' THEN | ||
| RAISE EXCEPTION 'assignment_record_category_code_check: classified assignment cannot become legacy_unspecified' | ||
| USING ERRCODE = 'check_violation', | ||
| CONSTRAINT = 'assignment_record_category_code_check', | ||
| TABLE = 'assignment_record', | ||
| SCHEMA = 'public'; | ||
| END IF; | ||
| END IF; | ||
|
|
||
| RETURN NEW; | ||
| END; | ||
| $$; | ||
|
|
||
| COMMENT ON FUNCTION public.enforce_assignment_category_write() IS | ||
| 'Rejects new or retroactively introduced legacy_unspecified assignment categories while preserving pre-contract system-time history.'; | ||
|
|
||
| -- PostgreSQL fires same-kind triggers in name order. This name intentionally | ||
| -- sorts before assignment_record_bitemporal_guard so a classified-to-sentinel | ||
| -- rewrite reports the category invariant before the generic history guard. | ||
| CREATE TRIGGER assignment_record_authoritative_category_guard | ||
| BEFORE INSERT OR UPDATE OF assignment_category_code ON public.assignment_record | ||
| FOR EACH ROW | ||
| EXECUTE FUNCTION public.enforce_assignment_category_write(); | ||
|
|
||
| COMMENT ON TRIGGER assignment_record_authoritative_category_guard ON public.assignment_record IS | ||
| 'Keeps legacy_unspecified as migration provenance instead of a writable assignment classification.'; | ||
|
|
||
| ALTER TABLE public.assignment_record | ||
| ADD CONSTRAINT assignment_record_primary_bitemporal_exclusion | ||
| EXCLUDE USING gist ( | ||
| tenant_record_id WITH =, | ||
| employment_record_id WITH =, | ||
| daterange(effective_from, effective_to, '[)') WITH &&, | ||
| tstzrange(recorded_from, recorded_to, '[)') WITH && | ||
| ) | ||
| WHERE (assignment_category_code = 'primary'); | ||
|
|
||
| COMMIT; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.