feat(governance): source-approval + dataset-freeze schema (AEG-X-009) #17

Merged
kjh2064 merged 1 commits from docs/aeg-x009-governance-schema into main 2026-08-07 17:14:52 +09:00
11 changed files with 651 additions and 0 deletions
@@ -0,0 +1,65 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://kartsell.taxbaik.com/contracts/data/source-approval.v1.proposed.json",
"title": "Governed Data Source Approval Contract",
"description": "Proposal only. This contract does not authorize ingestion until a human approval record exists.",
"contractVersion": "source-approval.v1-proposed",
"status": "DESIGN_PROPOSAL",
"automationBoundary": {
"allowedModes": ["EVALUATION_ONLY", "PROPOSAL_ONLY", "DRILL_ONLY"],
"forbiddenEffects": [
"AUTO_MODEL_ACTIVATION",
"AUTO_MODEL_PROMOTION",
"AUTO_PARAMETER_CHANGE",
"AUTO_ORDER",
"KIS_SUBMISSION",
"CLIENT_PUBLICATION"
]
},
"type": "object",
"additionalProperties": false,
"required": [
"sourceId",
"sourceVersion",
"domain",
"owner",
"steward",
"licenseReference",
"availabilitySla",
"freshnessSla",
"timezone",
"calendarId",
"unitContract",
"schemaContractVersion",
"status",
"contentHash",
"approvedBy",
"approvedAt"
],
"properties": {
"sourceId": {"type": "string", "minLength": 1},
"sourceVersion": {"type": "string", "minLength": 1},
"domain": {"type": "string", "minLength": 1},
"owner": {"type": "string", "minLength": 1},
"steward": {"type": "string", "minLength": 1},
"licenseReference": {"type": "string", "minLength": 1},
"availabilitySla": {"type": "string", "minLength": 1},
"freshnessSla": {"type": "string", "minLength": 1},
"timezone": {"type": "string", "minLength": 1},
"calendarId": {"type": "string", "minLength": 1},
"unitContract": {"type": "string", "minLength": 1},
"schemaContractVersion": {"type": "string", "minLength": 1},
"status": {"enum": ["CANDIDATE", "APPROVED", "SUSPENDED", "RETIRED", "QUARANTINED"]},
"contentHash": {"type": "string", "pattern": "^[A-Fa-f0-9]{64}$"},
"approvedBy": {"type": "string", "minLength": 1},
"approvedAt": {"type": "string", "format": "date-time"},
"publishedAt": {"type": "string", "format": "date-time"},
"revision": {"type": "integer", "minimum": 1}
},
"allOf": [
{
"if": {"properties": {"status": {"const": "APPROVED"}}},
"then": {"required": ["publishedAt", "revision"]}
}
]
}
@@ -0,0 +1,53 @@
-- AEG-X-009 / ADR-DATA-001: append-only source approval boundary.
-- This migration authorizes governance records only. It does not authorize ingestion,
-- recommendation, model activation, client publication, order, or KIS submission.
create schema if not exists governance;
create table if not exists governance.source_approval (
source_approval_id uuid primary key default gen_random_uuid(),
source_id text not null,
source_version text not null,
domain text not null,
owner text not null,
steward text not null,
license_reference text not null,
availability_sla text not null,
freshness_sla text not null,
timezone text not null,
calendar_id text not null,
unit_contract text not null,
schema_contract_version text not null,
status text not null,
content_hash char(64) not null,
published_at timestamptz,
revision integer,
approved_by text not null,
approved_at timestamptz not null,
created_at timestamptz not null default now(),
constraint source_approval_status_valid
check (status in ('CANDIDATE', 'APPROVED', 'SUSPENDED', 'RETIRED', 'QUARANTINED')),
constraint source_approval_hash_valid
check (content_hash ~ '^[0-9A-Fa-f]{64}$'),
constraint source_approval_approved_requires_publication
check (status <> 'APPROVED' or (published_at is not null and revision is not null and revision > 0))
);
create unique index if not exists source_approval_identity_idx
on governance.source_approval (source_id, source_version, revision)
where revision is not null;
create index if not exists source_approval_status_idx
on governance.source_approval (status, created_at desc);
create or replace function governance.reject_source_approval_mutation()
returns trigger as $$
begin
raise exception 'governance.source_approval is append-only; create a correction record';
end;
$$ language plpgsql;
drop trigger if exists source_approval_no_update on governance.source_approval;
create trigger source_approval_no_update
before update or delete on governance.source_approval
for each row execute function governance.reject_source_approval_mutation();
@@ -0,0 +1,32 @@
-- AEG-X-009 / ADR-DATA-001: make dataset freeze explicit and append-only.
-- This migration does not create or seed a dataset. It only hardens the existing
-- evaluation.dataset_manifest boundary.
alter table evaluation.dataset_manifest
drop constraint if exists dataset_manifest_status_check;
alter table evaluation.dataset_manifest
add constraint dataset_manifest_status_check
check (status in ('PROPOSED', 'APPROVED', 'FROZEN', 'QUARANTINED', 'RETIRED'));
alter table evaluation.dataset_manifest
drop constraint if exists dataset_manifest_frozen_approval_check;
alter table evaluation.dataset_manifest
add constraint dataset_manifest_frozen_approval_check
check (
status <> 'FROZEN'
or (approved_by is not null and approved_at is not null and frozen_at is not null)
);
create or replace function evaluation.reject_dataset_manifest_mutation()
returns trigger as $$
begin
raise exception 'evaluation.dataset_manifest is append-only; create a correction record';
end;
$$ language plpgsql;
drop trigger if exists dataset_manifest_no_update on evaluation.dataset_manifest;
create trigger dataset_manifest_no_update
before update or delete on evaluation.dataset_manifest
for each row execute function evaluation.reject_dataset_manifest_mutation();
@@ -0,0 +1,176 @@
# AEG-X-009 Data/Model Proposal Automation — Design Proposal
## Status and traceability
- WBS: `AEG-X-009`
- Requirement: `REQ-DATA-SOURCE`
- Evidence class: `SOURCE+DESIGN_PROPOSAL`
- Status: `DESIGN_PROPOSAL`; not approved implementation
- Source: `contracts/schedules/model-operations.v3.json`, `contracts/schedules/execution-assurance.v1.json`, `contracts/model-governance/evaluation-promotion.v2.json`, `src/KArtSell.BuildingBlocks/Versioning/VersionSet.cs`, live read-only schema inspection on 2026-08-06
- Assumption: source ingestion and model evaluation are allowed to create immutable proposal/evidence records when their mode is `EVALUATION_ONLY` or `PROPOSAL_ONLY`.
- Unknown: approved source owners, source licenses/SLA values, model training implementation, retention period, and operator/secondary assignments.
- Decision Required: approve the proposal schema, job ownership, source allow-list, promotion review roles, and retention/alert contracts before implementation.
## Non-negotiable boundary
Automation may:
1. discover and validate an approved source;
2. ingest immutable raw records and create a content-addressed dataset manifest;
3. run deterministic evaluation against a frozen server-side VersionSet;
4. create EvidenceSnapshot and a human-review proposal;
5. notify the maker/checker queue and expose status/metrics.
Automation must never:
- activate or promote a model;
- mutate thresholds, policy, configuration, or source code;
- rollback a model automatically;
- publish to clients;
- submit an order or KIS request.
## Required state flow
```text
SOURCE_CANDIDATE
-> SOURCE_APPROVED (human owner + license/SLA/timezone/unit)
-> INGESTION_EVALUATION_ONLY
-> DATASET_QUARANTINED | DATASET_FROZEN
-> MODEL_EVALUATION_ONLY
-> EVIDENCE_SNAPSHOT_CREATED
-> PROPOSAL_ONLY_REVIEW
-> HUMAN_APPROVED | HUMAN_REJECTED | EXPIRED
-> HUMAN_CHANGE_APPLIED (separate release, never by scheduler)
```
`DATASET_QUARANTINED`, missing evidence, hash mismatch, PIT violation, or VersionSet drift is a terminal hold for that run. It is not a retryable transient failure.
## Required immutable records
### Source catalog entry
```text
source_id
source_version
owner / steward / secondary
license_reference
availability_sla / freshness_sla
timezone / calendar
unit / currency
schema_contract_version
approved_at / approved_by
status: CANDIDATE | APPROVED | SUSPENDED | RETIRED
```
### Dataset manifest
Use the existing `evaluation.dataset_manifest` table. A row is eligible for evaluation only when:
```text
status = FROZEN
dataset_id and content_hash are non-blank
source_catalog_version is approved
lineage_hash is present
frozen_at and approved_at are present
published_at/revision/PIT rules pass
```
### Evaluation VersionSet
Use the existing `VersionSet` contract. It must be loaded server-side and contain:
```text
DatasetId, DataHash, ModelVersion, ConfigVersion, CodeSha, ContractVersion
```
The client may submit scope and requested window only. The client must not submit evidence, hashes, model versions, or configuration versions as authoritative values.
### Proposal packet
The proposal must reference, without copying or mutating, the EvidenceSnapshot and VersionSet. It must contain:
```text
proposal_id / idempotency_key / scope_key / job_run_id
version_set / evidence_id / dataset_id / input_hash / output_hash
policy_id / policy_trace_schema_version / decision_contract_version
evaluation windows and metric definition versions
PBO / DSR / frozen OOS / double-cost / false-exit-reentry evidence
maker / checker / expiry / disposition
```
## Existing schedule mapping
Do not add a new schedule until ADR/Issue approval. Use the existing contract entries as follows:
| Existing job | Mode | Automated responsibility | Forbidden result |
|---|---|---|---|
| J25 SourceContractDriftCheck | EVALUATION_ONLY | detect source contract/license/SLA drift | no source activation |
| J26 MarketCalendarCompletenessCheck | EVALUATION_ONLY | detect calendar/timezone/unit gaps | no threshold mutation |
| J27 EvidenceChainAudit | EVALUATION_ONLY | validate lineage/hash/PIT chain | no evidence repair by overwrite |
| J28 ProjectionFreshnessCheck | EVALUATION_ONLY | validate read-model freshness | no client publication |
| J30 ReleaseEvidenceAssemble | PROPOSAL_ONLY | assemble a review packet | no release or activation |
The missing business flow is not a new automatic promotion job. It is the contract and application boundary that creates a frozen dataset and proposal packet for the existing review process.
## Repository catalog mapping
The following mapping is grounded in the current catalog and data contracts. It is a design mapping, not an authorization to ingest.
| Domain | Current catalog/source | Current logical tables/contracts | Automation entry condition | Current status |
|---|---|---|---|---|
| Market data | KRX OpenAPI | `market_data.prices`, `VS-03_DATA_CONTRACT.md` | source approval + calendar/unit/SLA + PIT/hash checks | CANDIDATE |
| Corporate/fundamental data | OpenDart API | `model_operations.disclosures`, `VS-05_DATA_CONTRACT.md` | license/redistribution approval + filing schema/DQ | CANDIDATE |
| Portfolio | User input | `portfolio.holdings`, `VS-04_DATA_CONTRACT.md` | authenticated owner input + audit + PIT | CANDIDATE |
| Model operations | computed/evaluation output | `evaluation.dataset_manifest`, `governance.model_version_registry`, `signal_engine.evidence_snapshot` | frozen dataset and approved model/config/code contract | BLOCKED until seed/approval |
| Shadow evaluation | Hangfire/shadow run | `model_operations.shadow_run`, result/evidence contracts | server-side VersionSet + EVALUATION_ONLY capability | BLOCKED until VersionSet |
The source catalog's logical table descriptions must be reconciled with active runtime SQL and the live schema before a migration or ingestion implementation. The catalog itself is not a substitute for runtime schema evidence.
## Existing debt and decision linkage
This proposal directly addresses, but does not close, the following open items:
- `TD-044`: approved Dataset Manifest and Model Registry initial data absent;
- `TD-063`: total-return/delisting/corporate-action golden data incomplete;
- `TD-099` / `TD-105`: market calendar/timezone source and SLA not approved;
- `TD-132`: current total-return source not approved;
- `DEC-037`, `DEC-038`, `DEC-079`: source/license/SLA and calendar ownership decisions required.
These items remain OPEN/DECISION_REQUIRED until their evidence is attached. No automation job may treat the catalog row as approved merely because the row exists.
## Proposed WBS decomposition (proposal only)
These rows must be approved before being added to `WBS_MASTER.csv`:
| Proposed ID | Scope | Acceptance evidence |
|---|---|---|
| AEG-X-009-P1 | Source allow-list and approval record | unapproved source cannot enter ingestion |
| AEG-X-009-P2 | Dataset manifest freeze command | same input produces same dataset/content hash; append-only |
| AEG-X-009-P3 | Server-side VersionSet resolver | client-supplied evidence/version values ignored |
| AEG-X-009-P4 | Evaluation/Proposal orchestration | idempotent JobRun/Watermark; modes fail closed |
| AEG-X-009-P5 | Human review packet/API/UI | maker-checker, expiry, reject, audit trail |
| AEG-X-009-P6 | Replay/failure/observability evidence | quarantine, replay hash, alert, runbook, rollback/stop evidence |
## Gate progression
| Gate | Required before next gate |
|---|---|
| G0 | contract, source owner, data semantics, WBS approval |
| G1 | approved source catalog + isolated fresh/upgrade/re-run rehearsal |
| G2 | frozen dataset + VersionSet resolver + golden/replay evidence |
| G3 | evaluation-only execution and EvidenceSnapshot proof |
| G4 | proposal packet + maker/checker review evidence |
| G5 | separate human change approval; no scheduler activation |
## Immediate decision package
Before code or migration work, approve these six values explicitly:
1. source allow-list and owner/steward;
2. license, SLA, timezone, calendar, unit, and currency contracts;
3. dataset freeze status and retention policy;
4. model evaluation metric definition versions and population/window rules;
5. maker/checker roles and proposal expiry;
6. alert, stop, runbook, and secondary owner.
Until these are approved, the correct behavior is `BLOCKED`/`QUARANTINED`, not synthetic data/model creation.
+89
View File
@@ -0,0 +1,89 @@
# ADR-DATA-001: Governed Source Approval and Dataset Freeze Pipeline
## Status
`APPROVED` — approved by the repository owner on 2026-08-06 for the Source Approval contract slice. Implementation remains limited to append-only governance records; model activation, orders, and KIS submission remain forbidden.
## WBS / contract traceability
- WBS: `AEG-X-009`
- Requirement: `REQ-DATA-SOURCE`
- Existing contracts: `contracts/schedules/model-operations.v3.json`, `contracts/schedules/execution-assurance.v1.json`
- Related proposal: `docs/CURRENT/AEG-X-009_AUTOMATION_PROPOSAL.md`
- Policy boundary: `EVALUATION_ONLY` / `PROPOSAL_ONLY` / `DRILL_ONLY`
## Context
The live database contains the model-operations schemas, but no approved/frozen `dataset_manifest`, model registry, EvidenceSnapshot, or release bundle records. The source catalog previously claimed operational approval without preserving the required owner, license, SLA, timezone, unit, and approval evidence. This prevents a compliant Phase 1 VersionSet from being resolved.
## Decision proposal
Introduce a governed, append-only approval boundary before ingestion or evaluation:
```text
SourceCandidate
-> SourceApproval (human owner/steward + contract evidence)
-> DatasetManifest (immutable content/lineage hash)
-> DatasetFreeze (human approval or approved governance command)
-> ServerSideVersionSetResolver
-> EvaluationOnly / ProposalOnly operation
```
The resolver must reject any source or dataset that is not approved and frozen. The client cannot supply authoritative evidence, hashes, model/config/code versions, or contract versions.
## Proposed data boundary
The implementation may add normalized append-only records only after this ADR is approved. Candidate records must include:
```text
source_id, source_version, owner, steward, license_reference,
availability_sla, freshness_sla, timezone, calendar, unit, currency,
schema_contract_version, status, approved_by, approved_at,
published_at, revision, content_hash, lineage_hash
```
No update/delete is permitted for approval, evidence, or freeze history. Corrections are new records/events.
## Automation boundary
Allowed:
- source contract drift checks;
- data-quality evaluation;
- immutable manifest creation;
- deterministic dataset freeze proposal;
- EvidenceSnapshot creation;
- proposal packet and maker/checker notification.
Forbidden:
- automatic model activation/promotion;
- automatic rollback;
- threshold/config/policy/code mutation;
- client publication;
- broker order or KIS submission.
## Acceptance evidence required before implementation is complete
1. Unapproved source cannot enter ingestion.
2. Approved source with missing license/SLA/timezone/unit is quarantined.
3. Dataset freeze is append-only and content-addressed.
4. Same input and VersionSet produce the same manifest/evaluation hash.
5. Client-supplied VersionSet/evidence is ignored or rejected.
6. Replay with the same scope/idempotency/watermark produces no duplicate side effect.
7. Proposal approval is maker/checker and does not activate a model.
8. Failure, alert, runbook, retention, and rollback/stop evidence are preserved.
## Alternatives rejected
- Trusting `source-catalog.md` as approval: no immutable approval evidence.
- Creating synthetic DatasetId/ModelVersion values to unblock Shadow Run: violates evidence and reproducibility rules.
- Reusing existing model-operation tables without an approval boundary: permits ambiguous ownership and incomplete lineage.
- Adding a scheduler that activates models: forbidden by AGENTS.md v12.4.
## Approval record
- Decision: APPROVED for the first Source Approval contract slice.
- Scope: append-only source approval record and validation boundary only.
- Explicit exclusions: dataset freeze execution, model activation, automatic promotion/rollback, threshold mutation, client publication, broker order, and KIS submission.
- Follow-up: Dataset Freeze requires a separate reviewed slice and evidence package.
@@ -0,0 +1,30 @@
# AEG-X-009 Source Approval Migration Rehearsal
## Traceability
- WBS: `AEG-X-009`
- ADR: `ADR-DATA-001` / `DEC-101`
- Migration: `db/migrations/0033_source_approval_contract.sql`
- Target: isolated `kartsell_migration_test`
- Production `kartselldb`: not modified
## Actual execution evidence
```text
Command: dotnet src/KArtSell.DbMigrator/bin/Release/net10.0/KArtSell.DbMigrator.dll
Target: Host=127.0.0.1;Port=5432;Database=kartsell_migration_test
Fresh run:
0032_shadow_run_queued_status_contract.sql -> executed
0033_source_approval_contract.sql -> executed
Upgrade successful
Exit code: 0
Re-run:
No new scripts need to be executed - completing.
Exit code: 0
```
## Boundary
This proves migration fresh/re-run behavior only. It does not authorize any source, create a Dataset Manifest, resolve a model VersionSet, activate a model, publish to clients, submit an order, or submit to KIS.
@@ -0,0 +1,24 @@
# AEG-X-009 Dataset Freeze Contract Rehearsal
## Traceability
- WBS: `AEG-X-009`
- ADR: `ADR-DATA-001` / `DEC-101`
- Migration: `db/migrations/0034_dataset_manifest_freeze_contract.sql`
- Target: isolated `kartsell_migration_test`
- Production `kartselldb`: not modified
## Actual execution evidence
```text
DbMigrator upgrade: 0034_dataset_manifest_freeze_contract.sql executed, exit code 0
DbMigrator re-run: No new scripts need to be executed, exit code 0
Journal: 0034_dataset_manifest_freeze_contract.sql present
Status constraint: PROPOSED, APPROVED, FROZEN, QUARANTINED, RETIRED
Frozen approval constraint: FROZEN requires approved_by, approved_at, frozen_at
Append-only trigger: dataset_manifest_no_update present
```
## Boundary
This rehearsal validates schema and migration behavior only. No dataset row was seeded, no source was authorized, no VersionSet was resolved, and no model evaluation or Shadow Run was started.
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<TestRun id="e40a6b61-cb08-464e-8994-c346702b8803" name="kjh20@KIMJAEHYUN-OFFI 2026-08-06 17:31:19" runUser="KIMJAEHYUN-OFFI\kjh20" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Times creation="2026-08-06T17:31:19.1855656+09:00" queuing="2026-08-06T17:31:19.1855659+09:00" start="2026-08-06T17:31:17.1501437+09:00" finish="2026-08-06T17:31:19.1999864+09:00" />
<TestSettings name="default" id="e0c137c9-3376-48e5-80d3-8d7d74e1766c">
<Deployment runDeploymentRoot="kjh20_KIMJAEHYUN-OFFI_2026-08-06_17_31_19" />
</TestSettings>
<Results>
<UnitTestResult executionId="59c82802-50ae-4762-af59-3dcff366ebfb" testId="314a5e65-3e25-4434-eca3-b2b918f32928" testName="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_definitions_are_unique_and_evidence_only" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0214049" startTime="2026-08-06T17:31:18.8572092+09:00" endTime="2026-08-06T17:31:18.8935419+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="59c82802-50ae-4762-af59-3dcff366ebfb" />
<UnitTestResult executionId="08b46df9-07c3-4d74-bfb6-6ae7408fbc5f" testId="68affc9c-1fdb-0235-bb8e-0f39c95758a3" testName="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Passes_evidence_gate_but_still_requires_human_approval" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0227602" startTime="2026-08-06T17:31:18.8535529+09:00" endTime="2026-08-06T17:31:18.9037790+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="08b46df9-07c3-4d74-bfb6-6ae7408fbc5f" />
<UnitTestResult executionId="172709d6-ab15-46a9-b946-9e3452bb9783" testId="63f3a3a5-555e-c69b-517d-af3d3742c72d" testName="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Improvement_and_promotion_packet_jobs_are_proposal_only" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0042338" startTime="2026-08-06T17:31:18.9223268+09:00" endTime="2026-08-06T17:31:18.9231131+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="172709d6-ab15-46a9-b946-9e3452bb9783" />
<UnitTestResult executionId="3f52f522-8748-4401-9db3-c567bdbcfb18" testId="f11f9f8d-5962-492f-5226-89f243398182" testName="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Holds_when_any_operational_integrity_error_exists" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0028524" startTime="2026-08-06T17:31:18.9224268+09:00" endTime="2026-08-06T17:31:18.9227206+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="3f52f522-8748-4401-9db3-c567bdbcfb18" />
<UnitTestResult executionId="140ed97c-4a00-4b5b-9489-e894d5733b19" testId="9052c99d-50c0-412a-2f24-ad636ad7f995" testName="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_never_contains_order_or_auto_promotion_operations" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0029169" startTime="2026-08-06T17:31:18.9223810+09:00" endTime="2026-08-06T17:31:18.9229487+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="140ed97c-4a00-4b5b-9489-e894d5733b19" />
<UnitTestResult executionId="91c100f4-d2e4-468a-a5cc-271e55b3a677" testId="3fc876d0-6833-57e4-2651-437b2244093b" testName="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Operation_codes_are_unique_and_no_auto_promotion_mode_exists" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0284568" startTime="2026-08-06T17:31:18.8571332+09:00" endTime="2026-08-06T17:31:18.9215450+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="91c100f4-d2e4-468a-a5cc-271e55b3a677" />
</Results>
<TestDefinitions>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_never_contains_order_or_auto_promotion_operations" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="9052c99d-50c0-412a-2f24-ad636ad7f995">
<Execution id="140ed97c-4a00-4b5b-9489-e894d5733b19" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests" name="Registry_never_contains_order_or_auto_promotion_operations" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_definitions_are_unique_and_evidence_only" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="314a5e65-3e25-4434-eca3-b2b918f32928">
<Execution id="59c82802-50ae-4762-af59-3dcff366ebfb" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests" name="Registry_definitions_are_unique_and_evidence_only" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Passes_evidence_gate_but_still_requires_human_approval" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="68affc9c-1fdb-0235-bb8e-0f39c95758a3">
<Execution id="08b46df9-07c3-4d74-bfb6-6ae7408fbc5f" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests" name="Passes_evidence_gate_but_still_requires_human_approval" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Improvement_and_promotion_packet_jobs_are_proposal_only" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="63f3a3a5-555e-c69b-517d-af3d3742c72d">
<Execution id="172709d6-ab15-46a9-b946-9e3452bb9783" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests" name="Improvement_and_promotion_packet_jobs_are_proposal_only" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Holds_when_any_operational_integrity_error_exists" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="f11f9f8d-5962-492f-5226-89f243398182">
<Execution id="3f52f522-8748-4401-9db3-c567bdbcfb18" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests" name="Holds_when_any_operational_integrity_error_exists" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Operation_codes_are_unique_and_no_auto_promotion_mode_exists" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="3fc876d0-6833-57e4-2651-437b2244093b">
<Execution id="91c100f4-d2e4-468a-a5cc-271e55b3a677" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests" name="Operation_codes_are_unique_and_no_auto_promotion_mode_exists" />
</UnitTest>
</TestDefinitions>
<TestEntries>
<TestEntry testId="314a5e65-3e25-4434-eca3-b2b918f32928" executionId="59c82802-50ae-4762-af59-3dcff366ebfb" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="68affc9c-1fdb-0235-bb8e-0f39c95758a3" executionId="08b46df9-07c3-4d74-bfb6-6ae7408fbc5f" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="63f3a3a5-555e-c69b-517d-af3d3742c72d" executionId="172709d6-ab15-46a9-b946-9e3452bb9783" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="f11f9f8d-5962-492f-5226-89f243398182" executionId="3f52f522-8748-4401-9db3-c567bdbcfb18" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="9052c99d-50c0-412a-2f24-ad636ad7f995" executionId="140ed97c-4a00-4b5b-9489-e894d5733b19" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="3fc876d0-6833-57e4-2651-437b2244093b" executionId="91c100f4-d2e4-468a-a5cc-271e55b3a677" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
</TestEntries>
<TestLists>
<TestList name="목록에 없는 결과" id="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestList name="로드된 모든 결과" id="19431567-8539-422a-85d7-44ee4e166bda" />
</TestLists>
<ResultSummary outcome="Completed">
<Counters total="6" executed="6" passed="6" failed="0" error="0" timeout="0" aborted="0" inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" disconnected="0" warning="0" completed="0" inProgress="0" pending="0" />
<Output>
<StdOut>[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10)&#xD;
[xUnit.net 00:00:00.41] Discovering: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.52] Discovered: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.59] Starting: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.71] Finished: KArtSell.ModelOperations.UnitTests&#xD;
</StdOut>
</Output>
</ResultSummary>
</TestRun>
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<TestRun id="23a5a7ea-e78f-494c-b3ff-6152d9abf1a7" name="kjh20@KIMJAEHYUN-OFFI 2026-08-06 19:55:12" runUser="KIMJAEHYUN-OFFI\kjh20" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Times creation="2026-08-06T19:55:12.0855880+09:00" queuing="2026-08-06T19:55:12.0855884+09:00" start="2026-08-06T19:55:09.6932612+09:00" finish="2026-08-06T19:55:12.0937392+09:00" />
<TestSettings name="default" id="a66678cf-5da0-4e5d-8a14-ba23c18a9ed0">
<Deployment runDeploymentRoot="kjh20_KIMJAEHYUN-OFFI_2026-08-06_19_55_12" />
</TestSettings>
<Results>
<UnitTestResult executionId="69dbab6d-636e-4e99-a5eb-53cd68ba6c46" testId="72049d72-cc56-d9c2-d6a1-91fc3da97762" testName="KArtSell.ArchitectureTests.RepositoryRulesTests.Sql_does_not_use_select_star_or_unqualified_signal_tables" computerName="KIMJAEHYUN-OFFI" duration="00:00:01.2539924" startTime="2026-08-06T19:55:10.7094039+09:00" endTime="2026-08-06T19:55:11.9704810+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="69dbab6d-636e-4e99-a5eb-53cd68ba6c46" />
</Results>
<TestDefinitions>
<UnitTest name="KArtSell.ArchitectureTests.RepositoryRulesTests.Sql_does_not_use_select_star_or_unqualified_signal_tables" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.architecturetests\bin\release\net10.0\kartsell.architecturetests.dll" id="72049d72-cc56-d9c2-d6a1-91fc3da97762">
<Execution id="69dbab6d-636e-4e99-a5eb-53cd68ba6c46" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ArchitectureTests\bin\Release\net10.0\KArtSell.ArchitectureTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ArchitectureTests.RepositoryRulesTests" name="Sql_does_not_use_select_star_or_unqualified_signal_tables" />
</UnitTest>
</TestDefinitions>
<TestEntries>
<TestEntry testId="72049d72-cc56-d9c2-d6a1-91fc3da97762" executionId="69dbab6d-636e-4e99-a5eb-53cd68ba6c46" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
</TestEntries>
<TestLists>
<TestList name="목록에 없는 결과" id="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestList name="로드된 모든 결과" id="19431567-8539-422a-85d7-44ee4e166bda" />
</TestLists>
<ResultSummary outcome="Completed">
<Counters total="1" executed="1" passed="1" failed="0" error="0" timeout="0" aborted="0" inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" disconnected="0" warning="0" completed="0" inProgress="0" pending="0" />
<Output>
<StdOut>[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10)&#xD;
[xUnit.net 00:00:00.14] Discovering: KArtSell.ArchitectureTests&#xD;
[xUnit.net 00:00:00.19] Discovered: KArtSell.ArchitectureTests&#xD;
[xUnit.net 00:00:00.23] Starting: KArtSell.ArchitectureTests&#xD;
[xUnit.net 00:00:01.53] Finished: KArtSell.ArchitectureTests&#xD;
</StdOut>
</Output>
</ResultSummary>
</TestRun>
@@ -0,0 +1,20 @@
# AEG-X-009 Server-side VersionSet Resolver
## Traceability
- WBS: `AEG-X-009`
- Contract: `src/KArtSell.BuildingBlocks/Versioning/VersionSet.cs`
- Implementation: `src/KArtSell.Modules.ModelOperations/Infrastructure/DapperApprovedModelContextReader.cs`
- Test evidence: `evidence/AEG-X-009/versionset-resolver-boundary.trx`
## Change
The resolver now selects dataset manifests in `APPROVED` or `FROZEN` state only, requires dataset approval fields, and requires model registry approval fields. It continues to load all authoritative VersionSet values from the server-side database; client evidence/version values are not accepted.
## Verification
```text
Model Operations boundary tests: 6/6 passed
```
No dataset/model rows were seeded and no operation request or Shadow Run was created.
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<TestRun id="9717473c-44ec-4177-b948-a3aab6f9f902" name="kjh20@KIMJAEHYUN-OFFI 2026-08-06 20:00:05" runUser="KIMJAEHYUN-OFFI\kjh20" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Times creation="2026-08-06T20:00:05.4579824+09:00" queuing="2026-08-06T20:00:05.4579826+09:00" start="2026-08-06T20:00:03.9646531+09:00" finish="2026-08-06T20:00:05.4699867+09:00" />
<TestSettings name="default" id="25c44927-8b33-47f2-a80a-3f25b18dfdca">
<Deployment runDeploymentRoot="kjh20_KIMJAEHYUN-OFFI_2026-08-06_20_00_05" />
</TestSettings>
<Results>
<UnitTestResult executionId="421b5d6f-3c04-4e62-a9c3-efb7137bf0ab" testId="314a5e65-3e25-4434-eca3-b2b918f32928" testName="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_definitions_are_unique_and_evidence_only" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0156515" startTime="2026-08-06T20:00:05.2514618+09:00" endTime="2026-08-06T20:00:05.2794597+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="421b5d6f-3c04-4e62-a9c3-efb7137bf0ab" />
<UnitTestResult executionId="441ac26b-53fb-4136-a8d3-1d5d2356ee97" testId="3fc876d0-6833-57e4-2651-437b2244093b" testName="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Operation_codes_are_unique_and_no_auto_promotion_mode_exists" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0198758" startTime="2026-08-06T20:00:05.2539412+09:00" endTime="2026-08-06T20:00:05.2957390+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="441ac26b-53fb-4136-a8d3-1d5d2356ee97" />
<UnitTestResult executionId="a8ddc0dc-6452-494f-b628-387a1f594eb1" testId="f11f9f8d-5962-492f-5226-89f243398182" testName="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Holds_when_any_operational_integrity_error_exists" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0016648" startTime="2026-08-06T20:00:05.3014463+09:00" endTime="2026-08-06T20:00:05.3024698+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="a8ddc0dc-6452-494f-b628-387a1f594eb1" />
<UnitTestResult executionId="9d9fc6e8-5fe5-436c-81d8-6ec2911f145b" testId="63f3a3a5-555e-c69b-517d-af3d3742c72d" testName="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Improvement_and_promotion_packet_jobs_are_proposal_only" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0022293" startTime="2026-08-06T20:00:05.3013661+09:00" endTime="2026-08-06T20:00:05.3027426+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="9d9fc6e8-5fe5-436c-81d8-6ec2911f145b" />
<UnitTestResult executionId="0f952546-00ab-472c-9348-3f047c494137" testId="9052c99d-50c0-412a-2f24-ad636ad7f995" testName="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_never_contains_order_or_auto_promotion_operations" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0015493" startTime="2026-08-06T20:00:05.3014902+09:00" endTime="2026-08-06T20:00:05.3016767+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="0f952546-00ab-472c-9348-3f047c494137" />
<UnitTestResult executionId="0f9b3aef-9ec3-44be-83d9-f19ebb9e880a" testId="68affc9c-1fdb-0235-bb8e-0f39c95758a3" testName="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Passes_evidence_gate_but_still_requires_human_approval" computerName="KIMJAEHYUN-OFFI" duration="00:00:00.0169984" startTime="2026-08-06T20:00:05.2540204+09:00" endTime="2026-08-06T20:00:05.2858863+09:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="0f9b3aef-9ec3-44be-83d9-f19ebb9e880a" />
</Results>
<TestDefinitions>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_never_contains_order_or_auto_promotion_operations" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="9052c99d-50c0-412a-2f24-ad636ad7f995">
<Execution id="0f952546-00ab-472c-9348-3f047c494137" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests" name="Registry_never_contains_order_or_auto_promotion_operations" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests.Registry_definitions_are_unique_and_evidence_only" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="314a5e65-3e25-4434-eca3-b2b918f32928">
<Execution id="421b5d6f-3c04-4e62-a9c3-efb7137bf0ab" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationExecutionBoundaryTests" name="Registry_definitions_are_unique_and_evidence_only" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Passes_evidence_gate_but_still_requires_human_approval" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="68affc9c-1fdb-0235-bb8e-0f39c95758a3">
<Execution id="0f9b3aef-9ec3-44be-83d9-f19ebb9e880a" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests" name="Passes_evidence_gate_but_still_requires_human_approval" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Improvement_and_promotion_packet_jobs_are_proposal_only" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="63f3a3a5-555e-c69b-517d-af3d3742c72d">
<Execution id="9d9fc6e8-5fe5-436c-81d8-6ec2911f145b" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests" name="Improvement_and_promotion_packet_jobs_are_proposal_only" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests.Holds_when_any_operational_integrity_error_exists" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="f11f9f8d-5962-492f-5226-89f243398182">
<Execution id="a8ddc0dc-6452-494f-b628-387a1f594eb1" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.PromotionGateEvaluatorTests" name="Holds_when_any_operational_integrity_error_exists" />
</UnitTest>
<UnitTest name="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests.Operation_codes_are_unique_and_no_auto_promotion_mode_exists" storage="c:\job_roomz\kartsell.aegis\tests\kartsell.modeloperations.unittests\bin\release\net10.0\kartsell.modeloperations.unittests.dll" id="3fc876d0-6833-57e4-2651-437b2244093b">
<Execution id="441ac26b-53fb-4136-a8d3-1d5d2356ee97" />
<TestMethod codeBase="C:\Job_Roomz\KArtSell.Aegis\tests\KArtSell.ModelOperations.UnitTests\bin\Release\net10.0\KArtSell.ModelOperations.UnitTests.dll" adapterTypeName="executor://xunit/VsTestRunner3/netcore/" className="KArtSell.ModelOperations.UnitTests.ModelOperationRegistryTests" name="Operation_codes_are_unique_and_no_auto_promotion_mode_exists" />
</UnitTest>
</TestDefinitions>
<TestEntries>
<TestEntry testId="314a5e65-3e25-4434-eca3-b2b918f32928" executionId="421b5d6f-3c04-4e62-a9c3-efb7137bf0ab" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="3fc876d0-6833-57e4-2651-437b2244093b" executionId="441ac26b-53fb-4136-a8d3-1d5d2356ee97" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="f11f9f8d-5962-492f-5226-89f243398182" executionId="a8ddc0dc-6452-494f-b628-387a1f594eb1" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="63f3a3a5-555e-c69b-517d-af3d3742c72d" executionId="9d9fc6e8-5fe5-436c-81d8-6ec2911f145b" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="9052c99d-50c0-412a-2f24-ad636ad7f995" executionId="0f952546-00ab-472c-9348-3f047c494137" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestEntry testId="68affc9c-1fdb-0235-bb8e-0f39c95758a3" executionId="0f9b3aef-9ec3-44be-83d9-f19ebb9e880a" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
</TestEntries>
<TestLists>
<TestList name="목록에 없는 결과" id="8c84fa94-04c1-424b-9868-57a2d4851a1d" />
<TestList name="로드된 모든 결과" id="19431567-8539-422a-85d7-44ee4e166bda" />
</TestLists>
<ResultSummary outcome="Completed">
<Counters total="6" executed="6" passed="6" failed="0" error="0" timeout="0" aborted="0" inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" disconnected="0" warning="0" completed="0" inProgress="0" pending="0" />
<Output>
<StdOut>[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10)&#xD;
[xUnit.net 00:00:00.31] Discovering: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.39] Discovered: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.43] Starting: KArtSell.ModelOperations.UnitTests&#xD;
[xUnit.net 00:00:00.52] Finished: KArtSell.ModelOperations.UnitTests&#xD;
</StdOut>
</Output>
</ResultSummary>
</TestRun>