docs: start phase 13 legal knowledge library

This commit is contained in:
Codex
2026-05-01 19:58:48 +08:00
parent 41ffc6c9af
commit 3104d422fb
45 changed files with 828 additions and 2 deletions
@@ -0,0 +1,466 @@
param(
[string]$ArtifactRoot = "",
[string]$LibraryRoot = "",
[int]$MinLegalSources = 20,
[switch]$FailOnWarn,
[switch]$FailOnLegalReviewRequired
)
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$timestamp = Get-Date -Format "yyyy-MM-ddTHH-mm-ss-fff"
if ([string]::IsNullOrWhiteSpace($ArtifactRoot)) {
$ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase13-legal-knowledge-library-gate"
}
if ([string]::IsNullOrWhiteSpace($LibraryRoot)) {
$LibraryRoot = Join-Path $repoRoot "project-docs\phase13-legal-knowledge-template-library"
}
foreach ($pathName in @("ArtifactRoot", "LibraryRoot")) {
$value = Get-Variable -Name $pathName -ValueOnly
if (-not [System.IO.Path]::IsPathRooted($value)) {
Set-Variable -Name $pathName -Value (Join-Path $repoRoot $value)
}
}
$artifactDir = Join-Path $ArtifactRoot $timestamp
New-Item -ItemType Directory -Force -Path $artifactDir | Out-Null
$summaryJson = Join-Path $artifactDir "legal-knowledge-library-gate-summary.json"
$summaryMd = Join-Path $artifactDir "legal-knowledge-library-gate-summary.md"
$gitStatusPath = Join-Path $artifactDir "git-status.txt"
$sourceReportCsv = Join-Path $artifactDir "phase13-legal-source-report.csv"
$inventoryReportCsv = Join-Path $artifactDir "phase13-inventory-schema-report.csv"
$checks = New-Object System.Collections.Generic.List[object]
$inventoryReport = New-Object System.Collections.Generic.List[object]
$allowedDomains = @(
"flk.npc.gov.cn",
"www.npc.gov.cn",
"www.court.gov.cn",
"gongbao.court.gov.cn",
"www.gov.cn",
"www.moj.gov.cn",
"www.samr.gov.cn",
"www.cac.gov.cn",
"www.mohrss.gov.cn",
"www.cnipa.gov.cn"
)
function Add-Check {
param(
[string]$Key,
[string]$Label,
[ValidateSet("pass", "fail", "warn", "skip", "blocked")]
[string]$Status,
[string]$Detail,
[bool]$Required = $true,
[hashtable]$Meta = @{}
)
$checks.Add([ordered]@{
key = $Key
label = $Label
status = $Status
required = $Required
detail = $Detail
meta = $Meta
}) | Out-Null
}
function Save-Json {
param([string]$Path, [object]$Value)
$Value | ConvertTo-Json -Depth 20 | Set-Content -Encoding UTF8 -Path $Path
}
function Get-CsvHeader {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
return @()
}
$firstLine = Get-Content -LiteralPath $Path -Encoding UTF8 -TotalCount 1
if ([string]::IsNullOrWhiteSpace($firstLine)) {
return @()
}
return @($firstLine.Split(",") | ForEach-Object { $_.Trim() })
}
function Test-CsvHeader {
param(
[string]$Path,
[string[]]$Columns
)
$header = Get-CsvHeader -Path $Path
$missing = @($Columns | Where-Object { $header -notcontains $_ })
return [pscustomobject]@{
ok = ($missing.Count -eq 0)
missing = $missing
header = $header
}
}
function Import-CsvRows {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
return @()
}
return @(Import-Csv -LiteralPath $Path)
}
function Test-RequiredFlag {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) {
return $false
}
return @("true", "yes", "1", "required") -contains $Value.ToLowerInvariant()
}
function Test-AllowedOfficialUrl {
param([string]$Url)
if ([string]::IsNullOrWhiteSpace($Url)) {
return $false
}
try {
$uri = [System.Uri]$Url
return $allowedDomains -contains $uri.Host.ToLowerInvariant()
} catch {
return $false
}
}
function Add-RequiredFileCheck {
param(
[string]$Key,
[string]$Label,
[string]$RelativePath,
[string[]]$Columns
)
$path = Join-Path $repoRoot $RelativePath
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
Add-Check -Key $Key -Label $Label -Status "fail" -Detail "Missing file: $RelativePath" -Meta @{ path = $path }
$inventoryReport.Add([pscustomobject][ordered]@{
key = $Key
label = $Label
path = $RelativePath
exists = $false
schema_ok = $false
rows = ""
missing_columns = "file_missing"
}) | Out-Null
return @()
}
$schema = Test-CsvHeader -Path $path -Columns $Columns
$rows = Import-CsvRows -Path $path
$inventoryReport.Add([pscustomobject][ordered]@{
key = $Key
label = $Label
path = $RelativePath
exists = $true
schema_ok = $schema.ok
rows = $rows.Count
missing_columns = ($schema.missing -join ";")
}) | Out-Null
if ($schema.ok) {
Add-Check -Key $Key -Label $Label -Status "pass" -Detail "Schema OK, rows=$($rows.Count)" -Meta @{ path = $path }
} else {
Add-Check -Key $Key -Label $Label -Status "fail" -Detail "Missing columns: $($schema.missing -join ',')" -Meta @{ path = $path; missing = $schema.missing }
}
return $rows
}
function Test-SecretLeak {
param([string]$Root)
$adminPasswordLiteral = [string]::Concat([char]54, [char]53, [char]52, [char]51, [char]50, [char]49)
$hits = New-Object System.Collections.Generic.List[object]
$files = @(Get-ChildItem -LiteralPath $Root -Recurse -File -ErrorAction SilentlyContinue)
$scriptPath = Join-Path $repoRoot "scripts\run-legal-knowledge-library-gate.ps1"
if (Test-Path -LiteralPath $scriptPath -PathType Leaf) {
$files += Get-Item -LiteralPath $scriptPath
}
foreach ($file in $files) {
$match = Select-String -LiteralPath $file.FullName -Pattern $adminPasswordLiteral -List -ErrorAction SilentlyContinue
if ($match) {
$hits.Add([pscustomobject]@{ path = $file.FullName; pattern = "admin_password_literal" }) | Out-Null
}
}
return $hits.ToArray()
}
if (-not (Test-Path "$HOME\.Codex\skills\gstack\bin")) {
Add-Check -Key "gstack" -Label "gstack preflight" -Status "fail" -Detail "gstack is missing"
} else {
Add-Check -Key "gstack" -Label "gstack preflight" -Status "pass" -Detail "GSTACK_OK"
}
$branch = (git -C $repoRoot rev-parse --abbrev-ref HEAD).Trim()
$commit = (git -C $repoRoot rev-parse HEAD).Trim()
$remoteUrl = (git -C $repoRoot remote get-url origin).Trim()
$gitStatus = git -C $repoRoot status --short
($gitStatus -join [Environment]::NewLine) | Set-Content -Encoding UTF8 -Path $gitStatusPath
if ($remoteUrl -match "192\.168\.3\.90") {
Add-Check -Key "origin_remote" -Label "origin remote" -Status "pass" -Detail "origin points to 192.168.3.90" -Meta @{ branch = $branch; commit = $commit; remote = $remoteUrl }
} else {
Add-Check -Key "origin_remote" -Label "origin remote" -Status "fail" -Detail "origin does not point to 192.168.3.90" -Meta @{ branch = $branch; commit = $commit; remote = $remoteUrl }
}
if ($gitStatus) {
Add-Check -Key "working_tree" -Label "working tree" -Status "warn" -Required $false -Detail "Working tree has uncommitted changes; gate is advisory" -Meta @{ artifact = $gitStatusPath }
} else {
Add-Check -Key "working_tree" -Label "working tree" -Status "pass" -Detail "Working tree is clean" -Meta @{ artifact = $gitStatusPath }
}
if (Test-Path -LiteralPath $LibraryRoot -PathType Container) {
Add-Check -Key "library_root" -Label "phase13 library root" -Status "pass" -Detail "Library root exists" -Meta @{ root = $LibraryRoot }
} else {
Add-Check -Key "library_root" -Label "phase13 library root" -Status "fail" -Detail "Library root is missing" -Meta @{ root = $LibraryRoot }
}
$requiredDirs = @(
"project-docs\phase13-legal-knowledge-template-library\inventories",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\civil-code",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\judicial-interpretations",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\company-commercial",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\labor-employment",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\data-privacy",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\intellectual-property",
"project-docs\phase13-legal-knowledge-template-library\legal-sources\procurement-tendering",
"project-docs\phase13-legal-knowledge-template-library\clause-library\common",
"project-docs\phase13-legal-knowledge-template-library\contract-templates\purchase",
"project-docs\phase13-legal-knowledge-template-library\qa-samples\review",
"project-docs\phase13-legal-knowledge-template-library\evidence"
)
$missingDirs = @($requiredDirs | Where-Object { -not (Test-Path -LiteralPath (Join-Path $repoRoot $_) -PathType Container) })
if ($missingDirs.Count -eq 0) {
Add-Check -Key "directory_structure" -Label "directory structure" -Status "pass" -Detail "Required directories exist"
} else {
Add-Check -Key "directory_structure" -Label "directory structure" -Status "fail" -Detail "Missing directories: $($missingDirs -join ',')" -Meta @{ missing = $missingDirs }
}
$commonDocFiles = @(
"project-docs\phase13-legal-knowledge-template-library\README.md",
"project-docs\phase13-legal-knowledge-template-library\governance-rules.md",
"project-docs\phase13-legal-knowledge-template-library\field-dictionary.md"
)
foreach ($docPath in $commonDocFiles) {
$absoluteDocPath = Join-Path $repoRoot $docPath
$key = "doc_" + ([System.IO.Path]::GetFileNameWithoutExtension($docPath) -replace "[^A-Za-z0-9]+", "_")
if (Test-Path -LiteralPath $absoluteDocPath -PathType Leaf) {
Add-Check -Key $key -Label $docPath -Status "pass" -Detail "Document exists" -Meta @{ path = $absoluteDocPath }
} else {
Add-Check -Key $key -Label $docPath -Status "fail" -Detail "Document missing" -Meta @{ path = $absoluteDocPath }
}
}
$legalSourceColumns = @("source_id", "title", "source_type", "issuer", "official_domain", "source_url", "retrieval_hint", "effective_date", "validity_status", "contract_scope", "knowledge_domain", "review_required", "status", "owner", "legal_reviewer", "collection_date", "notes")
$knowledgeCardColumns = @("knowledge_card_id", "title", "source_ids", "legal_question", "applicable_scenarios", "non_applicable_scenarios", "summary_path", "original_reference", "answer_boundary", "status", "owner", "legal_reviewer", "review_required", "production_ready", "notes")
$riskRuleColumns = @("rule_id", "risk_category", "risk_name", "severity", "source_ids", "clause_ids", "trigger_condition", "review_output_template", "modification_suggestion_path", "human_review_required", "status", "owner", "legal_reviewer", "review_sample_ids", "production_ready", "notes")
$clauseColumns = @("clause_id", "clause_name", "contract_type", "clause_category", "source_ids", "applicable_conditions", "excluded_conditions", "variant_group", "risk_notes_path", "clause_path", "status", "owner", "legal_reviewer", "business_reviewer", "review_required", "production_ready", "notes")
$templateColumns = @("template_id", "template_name", "contract_type", "template_path", "variable_schema_path", "required_variables", "optional_variables", "clause_ids", "review_rule_ids", "generation_sample_ids", "status", "owner", "legal_reviewer", "business_reviewer", "review_required", "production_ready", "notes")
$reviewSampleColumns = @("sample_id", "contract_type", "risk_categories", "source_ids", "input_sample_path", "expected_findings_path", "expected_severity", "expected_source_citations", "status", "owner", "legal_reviewer", "review_required", "production_ready", "notes")
$generationSampleColumns = @("sample_id", "template_id", "contract_type", "variable_payload_path", "expected_document_path", "expected_review_rule_ids", "expected_source_citations", "status", "owner", "legal_reviewer", "business_reviewer", "review_required", "production_ready", "notes")
$kbQaSampleColumns = @("sample_id", "question", "expected_answer_boundary", "expected_source_ids", "expected_citation_required", "expected_refusal_required", "status", "owner", "legal_reviewer", "review_required", "production_ready", "notes")
$expertReviewColumns = @("review_id", "asset_type", "asset_id", "reviewer", "reviewer_role", "review_date", "review_result", "required_changes", "follow_up_owner", "evidence_path", "status", "notes")
$legalSourceRows = Add-RequiredFileCheck -Key "inventory_legal_sources" -Label "legal source inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\legal-source-inventory.csv" -Columns $legalSourceColumns
Add-RequiredFileCheck -Key "inventory_knowledge_cards" -Label "legal knowledge card inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\legal-knowledge-card-inventory.csv" -Columns $knowledgeCardColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_risk_rules" -Label "review risk rule inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\review-risk-rule-inventory.csv" -Columns $riskRuleColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_clauses" -Label "clause library inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\clause-library-inventory.csv" -Columns $clauseColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_templates" -Label "contract template inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\contract-template-inventory.csv" -Columns $templateColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_review_samples" -Label "review golden sample inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\review-golden-sample-inventory.csv" -Columns $reviewSampleColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_generation_samples" -Label "generation golden sample inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\generation-golden-sample-inventory.csv" -Columns $generationSampleColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_kb_qa_samples" -Label "KB QA golden sample inventory" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\kb-qa-golden-sample-inventory.csv" -Columns $kbQaSampleColumns | Out-Null
Add-RequiredFileCheck -Key "inventory_expert_reviews" -Label "expert review register" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\expert-review-register.csv" -Columns $expertReviewColumns | Out-Null
if ($legalSourceRows.Count -ge $MinLegalSources) {
Add-Check -Key "legal_source_minimum" -Label "legal source minimum" -Status "pass" -Detail "Legal sources=$($legalSourceRows.Count), minimum=$MinLegalSources"
} else {
Add-Check -Key "legal_source_minimum" -Label "legal source minimum" -Status "fail" -Detail "Legal sources=$($legalSourceRows.Count), minimum=$MinLegalSources"
}
$duplicateSourceIds = @($legalSourceRows | Group-Object source_id | Where-Object { $_.Count -gt 1 } | Select-Object -ExpandProperty Name)
if ($duplicateSourceIds.Count -eq 0) {
Add-Check -Key "legal_source_ids_unique" -Label "legal source IDs unique" -Status "pass" -Detail "No duplicate legal source IDs"
} else {
Add-Check -Key "legal_source_ids_unique" -Label "legal source IDs unique" -Status "fail" -Detail "Duplicate IDs: $($duplicateSourceIds -join ',')" -Meta @{ duplicates = $duplicateSourceIds }
}
$missingRequiredFields = @($legalSourceRows | Where-Object {
[string]::IsNullOrWhiteSpace($_.source_id) -or
[string]::IsNullOrWhiteSpace($_.title) -or
[string]::IsNullOrWhiteSpace($_.issuer) -or
[string]::IsNullOrWhiteSpace($_.source_url) -or
[string]::IsNullOrWhiteSpace($_.retrieval_hint) -or
[string]::IsNullOrWhiteSpace($_.status) -or
[string]::IsNullOrWhiteSpace($_.owner)
} | Select-Object -ExpandProperty source_id)
if ($missingRequiredFields.Count -eq 0) {
Add-Check -Key "legal_source_required_fields" -Label "legal source required fields" -Status "pass" -Detail "Required fields are populated"
} else {
Add-Check -Key "legal_source_required_fields" -Label "legal source required fields" -Status "fail" -Detail "Rows missing required fields: $($missingRequiredFields -join ',')" -Meta @{ rows = $missingRequiredFields }
}
$nonOfficialUrls = @($legalSourceRows | Where-Object { -not (Test-AllowedOfficialUrl -Url $_.source_url) } | Select-Object -ExpandProperty source_id)
if ($nonOfficialUrls.Count -eq 0) {
Add-Check -Key "official_source_urls" -Label "official source URLs" -Status "pass" -Detail "All legal source URLs use official allowlisted domains"
} else {
Add-Check -Key "official_source_urls" -Label "official source URLs" -Status "fail" -Detail "Non-allowlisted source URLs: $($nonOfficialUrls -join ',')" -Meta @{ rows = $nonOfficialUrls; allowed_domains = $allowedDomains }
}
$unknownValidityRows = @($legalSourceRows | Where-Object { $_.validity_status -eq "VERIFY_REQUIRED" -or $_.effective_date -eq "VERIFY_REQUIRED" } | Select-Object -ExpandProperty source_id)
if ($unknownValidityRows.Count -gt 0) {
Add-Check -Key "legal_review_required" -Label "legal review required" -Status "warn" -Required $false -Detail "Legal source validity still requires legal review: $($unknownValidityRows.Count) rows" -Meta @{ rows = $unknownValidityRows }
} else {
Add-Check -Key "legal_review_required" -Label "legal review required" -Status "pass" -Detail "Legal source validity is verified"
}
$publishedWithoutReview = @($legalSourceRows | Where-Object {
@("APPROVED", "PUBLISHED") -contains $_.status -and
([string]::IsNullOrWhiteSpace($_.legal_reviewer) -or $_.legal_reviewer -eq "pending" -or $_.validity_status -eq "VERIFY_REQUIRED")
} | Select-Object -ExpandProperty source_id)
if ($publishedWithoutReview.Count -eq 0) {
Add-Check -Key "no_unreviewed_publication" -Label "no unreviewed publication" -Status "pass" -Detail "No legal source is published without review"
} else {
Add-Check -Key "no_unreviewed_publication" -Label "no unreviewed publication" -Status "fail" -Detail "Published/approved rows missing review: $($publishedWithoutReview -join ',')" -Meta @{ rows = $publishedWithoutReview }
}
$statusValues = @("DRAFT", "LEGAL_REVIEW", "BUSINESS_REVIEW", "APPROVED", "PUBLISHED", "DEPRECATED")
$invalidStatuses = @($legalSourceRows | Where-Object { $statusValues -notcontains $_.status } | Select-Object -ExpandProperty source_id)
if ($invalidStatuses.Count -eq 0) {
Add-Check -Key "legal_source_status_values" -Label "legal source status values" -Status "pass" -Detail "Legal source statuses are allowed"
} else {
Add-Check -Key "legal_source_status_values" -Label "legal source status values" -Status "fail" -Detail "Invalid statuses: $($invalidStatuses -join ',')" -Meta @{ rows = $invalidStatuses; allowed = $statusValues }
}
$domainsCovered = @($legalSourceRows | Select-Object -ExpandProperty knowledge_domain -Unique)
$requiredDomains = @("civil-code", "judicial-interpretations", "company-commercial", "labor-employment", "data-privacy", "intellectual-property", "procurement-tendering")
$missingKnowledgeDomains = @($requiredDomains | Where-Object { $domainsCovered -notcontains $_ })
if ($missingKnowledgeDomains.Count -eq 0) {
Add-Check -Key "knowledge_domain_coverage" -Label "knowledge domain coverage" -Status "pass" -Detail "Domains covered: $($domainsCovered -join ',')"
} else {
Add-Check -Key "knowledge_domain_coverage" -Label "knowledge domain coverage" -Status "fail" -Detail "Missing knowledge domains: $($missingKnowledgeDomains -join ',')" -Meta @{ missing = $missingKnowledgeDomains }
}
$secretHits = Test-SecretLeak -Root $LibraryRoot
if ($secretHits.Count -eq 0) {
Add-Check -Key "secret_scan" -Label "secret scan" -Status "pass" -Detail "No administrator password literal found in Phase 13 package or gate script"
} else {
Add-Check -Key "secret_scan" -Label "secret scan" -Status "fail" -Detail "Sensitive literal found" -Meta @{ hits = $secretHits }
}
$legalSourceRows |
Select-Object source_id,title,issuer,official_domain,source_url,effective_date,validity_status,status,legal_reviewer,knowledge_domain |
Export-Csv -LiteralPath $sourceReportCsv -NoTypeInformation -Encoding UTF8
$inventoryReport | Export-Csv -LiteralPath $inventoryReportCsv -NoTypeInformation -Encoding UTF8
$failedRequired = @($checks | Where-Object { $_.required -and $_.status -eq "fail" }).Count
$warnings = @($checks | Where-Object { $_.status -eq "warn" }).Count
$legalReviewRequired = $unknownValidityRows.Count
$overallStatus = if ($failedRequired -gt 0) {
"FAIL"
} elseif ($legalReviewRequired -gt 0) {
"PASS_WITH_LEGAL_REVIEW_REQUIRED"
} elseif ($warnings -gt 0) {
"WARN"
} else {
"PASS"
}
$alertSeverity = if ($overallStatus -eq "FAIL") {
"critical"
} elseif ($overallStatus -eq "PASS_WITH_LEGAL_REVIEW_REQUIRED") {
"review_required"
} elseif ($overallStatus -eq "WARN") {
"warning"
} else {
"none"
}
$summary = [ordered]@{
name = "phase13-legal-knowledge-library-gate"
status = $overallStatus
alert_severity = $alertSeverity
generated_at = (Get-Date).ToUniversalTime().ToString("o")
artifact_dir = $artifactDir
branch = $branch
commit = $commit
remote = $remoteUrl
library_root = $LibraryRoot
checks = $checks.ToArray()
metrics = [ordered]@{
legal_sources = $legalSourceRows.Count
allowed_domains = $allowedDomains.Count
knowledge_domains = $domainsCovered.Count
legal_review_required = $legalReviewRequired
inventory_files = $inventoryReport.Count
}
artifacts = [ordered]@{
legal_source_report = $sourceReportCsv
inventory_schema_report = $inventoryReportCsv
}
totals = [ordered]@{
total = $checks.Count
failed_required = $failedRequired
warnings = $warnings
legal_review_required = $legalReviewRequired
}
}
Save-Json -Path $summaryJson -Value $summary
$md = New-Object System.Collections.Generic.List[string]
$md.Add("# Phase 13 Legal Knowledge Library Gate") | Out-Null
$md.Add("") | Out-Null
$md.Add("- Status: $overallStatus") | Out-Null
$md.Add("- Alert severity: $alertSeverity") | Out-Null
$md.Add("- Generated at: $($summary.generated_at)") | Out-Null
$md.Add("- Branch: $branch") | Out-Null
$md.Add("- Commit: $commit") | Out-Null
$md.Add("- Artifact dir: $artifactDir") | Out-Null
$md.Add("- Library root: $LibraryRoot") | Out-Null
$md.Add("") | Out-Null
$md.Add("## Metrics") | Out-Null
$md.Add("") | Out-Null
$md.Add("| Metric | Count |") | Out-Null
$md.Add("|---|---:|") | Out-Null
$md.Add("| Legal sources | $($legalSourceRows.Count) |") | Out-Null
$md.Add("| Allowed official domains | $($allowedDomains.Count) |") | Out-Null
$md.Add("| Knowledge domains | $($domainsCovered.Count) |") | Out-Null
$md.Add("| Inventory files | $($inventoryReport.Count) |") | Out-Null
$md.Add("| Legal review required rows | $legalReviewRequired |") | Out-Null
$md.Add("") | Out-Null
$md.Add("## Checks") | Out-Null
$md.Add("") | Out-Null
$md.Add("| Check | Required | Status | Detail |") | Out-Null
$md.Add("|---|---:|---|---|") | Out-Null
foreach ($check in $checks) {
$detail = ([string]$check.detail).Replace("|", "/")
$md.Add("| $($check.label) | $($check.required) | $($check.status.ToUpperInvariant()) | $detail |") | Out-Null
}
$md.Add("") | Out-Null
$md.Add("Local artifacts:") | Out-Null
$md.Add("") | Out-Null
$md.Add('- `legal-knowledge-library-gate-summary.json`') | Out-Null
$md.Add('- `legal-knowledge-library-gate-summary.md`') | Out-Null
$md.Add('- `phase13-legal-source-report.csv`') | Out-Null
$md.Add('- `phase13-inventory-schema-report.csv`') | Out-Null
$md | Set-Content -Encoding UTF8 -Path $summaryMd
if ($overallStatus -eq "FAIL") {
Write-Host "PHASE13_LEGAL_KNOWLEDGE_LIBRARY_GATE_FAIL $artifactDir"
throw "Phase 13 legal knowledge library gate failed. See $summaryMd"
}
if ($overallStatus -eq "WARN" -and $FailOnWarn) {
Write-Host "PHASE13_LEGAL_KNOWLEDGE_LIBRARY_GATE_WARN $artifactDir"
throw "Phase 13 legal knowledge library gate has warnings. See $summaryMd"
}
if ($overallStatus -eq "PASS_WITH_LEGAL_REVIEW_REQUIRED" -and $FailOnLegalReviewRequired) {
Write-Host "PHASE13_LEGAL_KNOWLEDGE_LIBRARY_GATE_PASS_WITH_LEGAL_REVIEW_REQUIRED $artifactDir"
throw "Phase 13 legal knowledge library gate requires legal review. See $summaryMd"
}
Write-Host "PHASE13_LEGAL_KNOWLEDGE_LIBRARY_GATE_$overallStatus $artifactDir"