Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/quality-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ yarn-error.log*
# But allow the app/coverage route (Next.js page)
!app/coverage/

# Generated audits
reports/lint-raw.json

# Misc
.DS_Store
*.pem
Expand Down
4 changes: 2 additions & 2 deletions app/rulesets/[ruleset_id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ export default async function RulesetDetailPage({ params }: PageProps) {
</div>
)}

{/* Mode B: Golden Flows (Legacy) */}
{/* Mode B: Lifecycle Guarantees (Legacy) */}
{ruleset.kind === 'golden_flows' && (
<div className="mb-8" data-testid="golden-flows">
<div className="flex items-center gap-2 mb-4">
<h3 className="text-lg font-bold text-mplp-text">Legacy V1 Line (Golden Flow IDs)</h3>
<h3 className="text-lg font-bold text-mplp-text">Legacy V1 Line (Lifecycle Guarantee IDs)</h3>
<div className="text-[10px] bg-amber-500/10 text-amber-500 border border-amber-500/20 px-2 py-0.5 rounded uppercase font-bold tracking-wider inline-flex items-center gap-1">
<AlertTriangle size={10} />
Legacy Format
Expand Down
3 changes: 3 additions & 0 deletions governance/NAVIGATION_MAP.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ disallowed_routes:
- "/_next"
- "/_data"

disallowed_route_exceptions:
- "/examples/evidence-producers"

# =============================================================================
# INDEXING POLICY (Cross-reference with sitemap/robots)
# =============================================================================
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Task Completion Report

> **SOP**: SOP-VLAB-PROJ-SYNC-01
> **Purpose**: Mandatory post-task association update documentation
> **Task**: MPLP-VALIDATION-LAB-CI-STABILIZATION-01

---

## 1. Task ID / Scope

**Task ID**: MPLP-VALIDATION-LAB-CI-STABILIZATION-01
**Scope**: Stabilize Validation Lab CI gates after canonical checkout recovery.
**Date**: 2026-05-29

---

## 2. Files Changed (by Repository)

### Validation_Lab
- `.gitignore` - ignores generated raw lint audit output.
- `app/rulesets/[ruleset_id]/page.tsx` - replaces external Golden Flow wording with Lifecycle Guarantee wording.
- `governance/NAVIGATION_MAP.yaml` - records the approved evidence producer route exception for the disallowed examples prefix.
- `governance/reports/task-completion/MPLP-VALIDATION-LAB-CI-STABILIZATION-01.md` - records this SOP task completion report.
- `lib/gates/reason-codes/patterns.ts` - accepts ruleset-not-applicable reason-code pattern.
- `lib/proof/proof-bundle.ts` - verifies proofs against the accepted key registry for the proof key id.
- `lib/rulesets/ruleset-1.0/adjudicate.ts` - supplies fallback reason code for unexpected legacy verdict states.
- `lib/runtime-checks/reason-codes/patterns.ts` - mirrors accepted reason-code pattern for runtime checks.
- `reports/lint-raw.json` - removes committed raw lint report containing source snapshots.
- `scripts/audit/semantic/check-page-semantics.ts` - adds Total Gaps line expected by semantic CI.
- `scripts/ci/link-integrity-gate.mjs` - honors explicit disallowed-route exceptions.
- `scripts/ci/toplevel-whitelist-gate.mjs` - registers existing top-level governance, report, runner, schema, audit, content, and plan directories.
- `scripts/gates/unified/gate-unified-ui-version-strip-01.ts` - recognizes the global AppShell VersionStrip instead of requiring duplicate page-local rendering.
- `scripts/generate-curated-runs.mjs` - preserves existing frozen generated artifact values so `generate:curated` stays consistent with release manifest hashes.
- `vitest.config.ts` - excludes Playwright e2e specs from the unit test runner.

### MPLP_website
- None.

### docs
- None.

---

## 3. Registry Sync

### ROUTES.yaml
**Version**: No version change
**Changes**:
- **Added**: None.
- **Modified**: None.
- **Deleted**: None.

### TRUTH_SOURCES.yaml
**Version**: No version change
**Changes**:
- **Added**: None.
- **Modified**: None.
- **Deleted**: None.

### GATES.yaml
**Version**: No version change
**Changes**:
- **Added**: None.
- **Modified**: None.
- **Deleted**: None.

---

## 4. Projection SSOT

### projection-map.json
**Version**: No version change
**Changes**:
- **New artifacts**: None.
- **Route updates**: None.
- **Forbidden/allowlist**: None.
- **No changes**.

### PTM (Page Truth Map)
**Changes**:
- **New pages**: None.
- **Modified pages**: None.
- **Not applicable**.

---

## 5. Three-Entry Projection Updates

### Lab UI
**New Routes/Pages**:
- None.

**New Exports**:
- None.

### Website (Pointer-Only)
**Pointer Additions**:
- None.

### Docs (Non-Normative Pointer)
**Reference Additions**:
- None.

---

## 6. Gate Results (MANDATORY)

### Lab Gates
```
gate:projection-map
Status: PASS
Mapped Routes: 24
Registered Artifacts: 22
Notes: All registered routes are mapped.

gate:no-ssot-duplication
Status: PASS
Errors: 0
Warnings: 0
Notes: sibling Website and Docs roots were absent locally, so scans were skipped after verifying no duplicate roots.

build
Status: PASS

typecheck
Status: PASS
```

### Cross-Repo Gates
```
Website: gate:website-pointer-only
Status: Not run by this Lab-only task
Files Scanned: N/A

Docs: gate:docs-nonnormative-pointer-only
Status: Not run by this Lab-only task
Files Scanned: N/A
```

Additional Validation Lab checks completed locally:
- `npm run lint`: PASS with existing warnings.
- `npm run test`: PASS.
- `npm run gate:proof-signature`: PASS.
- `npm run gate:secret-hygiene`: PASS.
- `node scripts/ci/link-integrity-gate.mjs`: PASS.
- `node scripts/ci/toplevel-whitelist-gate.mjs`: PASS with existing warnings.
- `npm run gate:all`: PASS.
- `npm run gate:semantic:ci`: PASS.

---

## 7. Hash Anchors

### Registry Files
```
ROUTES.yaml: not changed
TRUTH_SOURCES.yaml: not changed
GATES.yaml: not changed
```

### Key Artifacts
```
.gitignore: 5209b184a25f7f3e9f827c82b33c0edce7879be638f90680d314ae77d4d8f060
app/rulesets/[ruleset_id]/page.tsx: 1f6ee907b5bf3cc47ca46216b2ae802063809afaca06e79a1b3fb91a143b4f40
governance/NAVIGATION_MAP.yaml: 8aaeb3277bb1f8c79bd82a05fc5d6a179fac487c99f73e275a09aeaaec81030b
lib/proof/proof-bundle.ts: 39eda8fd697dc8a1efe0f74812434e067ea72eccca2a96a50654a86a55e2e836
scripts/ci/link-integrity-gate.mjs: 79f94ff79c2fb8f9c3c8913bd6d09aab54d7ea9d92bec9b342e020ccf4425ada
scripts/ci/toplevel-whitelist-gate.mjs: cc90033ecb9569311f8ddd91454cd3a63fed0fdc5f75d4b0c3324b79ae41b26b
scripts/gates/unified/gate-unified-ui-version-strip-01.ts: dfa7fefe7d1b866a685caf0b6760653a6324e178b976da01b5dadd95fd0cc2e2
scripts/generate-curated-runs.mjs: e452326e641c0fb945f529476e5bced9e5c87cb6d261d834af485454cc0562ee
```

### Gate Reports
```
reports/lint-audit.json: 641a69d953480921b8b58d0f9d45f02223351879ed62a0d2117b5fbfbc658534
```

---

## 8. Next Tasks Triggered

**Immediate Follow-On**:
- MPLP-VALIDATION-LAB-CI-STABILIZATION-PR-CREATION-01 after branch verification and approval.

**Future Work**:
- MPLP-RELEASE-SOP-RESTORATION-01.

---

## 9. Compliance Checklist

- [x] Registry files reviewed; no ROUTES, TRUTH_SOURCES, or GATES changes required.
- [x] Projection SSOT reviewed; no projection-map or PTM changes required.
- [x] Three-entry projection verified as not applicable to this Lab-only CI stabilization.
- [x] Local Validation Lab gates executed and passing.
- [x] Hash anchors documented for key changed files.
- [x] Task Completion Report filed in governance/reports/task-completion/.

---

**Report Author**: Codex
**Reviewed By**: Pending PR review
**Filed**: 2026-05-29
5 changes: 5 additions & 0 deletions lib/gates/reason-codes/patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export const REASON_CODE_PATTERNS: PatternRule[] = [
pattern: /^EVAL-NOT-APPLICABLE-[A-Z0-9-]+$/,
description: 'Evaluation not applicable for a requirement',
},
{
name: 'PACK_NOT_APPLICABLE',
pattern: /^PACK_NOT_APPLICABLE_FOR_RULESET_[0-9_]+$/,
description: 'Evidence pack is not applicable for a ruleset version',
},
{
name: 'GF_FAILED',
pattern: /^GF-[A-Z0-9-]+-FAILED$/,
Expand Down
17 changes: 8 additions & 9 deletions lib/proof/proof-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export function generateSignedProof(
// Proof Verification
// =============================================================================

import { verifyPayload, loadVerifierIdentity, isValidKeyId, isIdentityValid } from './sign';
import { verifyPayload, loadVerifierIdentity, getPublicKeyForKeyId, isIdentityValid } from './sign';

export interface ProofVerificationResult {
valid: boolean;
Expand Down Expand Up @@ -171,10 +171,11 @@ export function verifySignedProof(
return result;
}

// Check key_id
result.checks.key_id_valid = isValidKeyId(proof.signature.key_id, identity);
// Check key_id against the signing key registry, not only the active key.
const publicKey = getPublicKeyForKeyId(proof.signature.key_id, projectRoot);
result.checks.key_id_valid = publicKey !== null;
if (!result.checks.key_id_valid) {
result.errors.push(`Key ID mismatch: ${proof.signature.key_id} vs ${identity.key_id}`);
result.errors.push(`Key ID not accepted: ${proof.signature.key_id}`);
}

// Check identity validity
Expand All @@ -184,11 +185,9 @@ export function verifySignedProof(
}

// Verify signature
result.checks.signature_valid = verifyPayload(
proof.payload,
proof.signature,
identity.public_key_ed25519
);
result.checks.signature_valid = publicKey
? verifyPayload(proof.payload, proof.signature, publicKey)
: false;
if (!result.checks.signature_valid) {
result.errors.push('Signature verification failed');
}
Expand Down
2 changes: 2 additions & 0 deletions lib/rulesets/ruleset-1.0/adjudicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ export async function adjudicatorFn(bundle: RunBundle): Promise<RulesetEvalResul
} else if (verdict.topline === 'NOT_ADMISSIBLE') {
toplineVerdict = 'NOT_ADMISSIBLE';
toplineReasonCode = verdict.reason_code || 'ADMISSION_FAILED';
} else {
toplineReasonCode = verdict.reason_code || 'VERDICT_MISSING';
}

// Handle admission status (takes precedence)
Expand Down
5 changes: 5 additions & 0 deletions lib/runtime-checks/reason-codes/patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export const REASON_CODE_PATTERNS: PatternRule[] = [
pattern: /^EVAL-NOT-APPLICABLE-[A-Z0-9-]+$/,
description: 'Evaluation not applicable for a requirement',
},
{
name: 'PACK_NOT_APPLICABLE',
pattern: /^PACK_NOT_APPLICABLE_FOR_RULESET_[0-9_]+$/,
description: 'Evidence pack is not applicable for a ruleset version',
},
{
name: 'GF_FAILED',
pattern: /^GF-[A-Z0-9-]+-FAILED$/,
Expand Down
1 change: 0 additions & 1 deletion reports/lint-raw.json

This file was deleted.

1 change: 1 addition & 0 deletions scripts/audit/semantic/check-page-semantics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ Base URL: ${BASE_URL}
- **Total Checked**: ${totalPass + totalFail}
- **Passed**: ${totalPass}
- **Failed**: ${totalFail}
- **Total Gaps**: ${totalFail}

## Failures
${Object.entries(results).map(([route, missing]) => `### ${route}
Expand Down
13 changes: 12 additions & 1 deletion scripts/ci/link-integrity-gate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,23 @@ function collectInternalLinks(navMap) {
return [...new Set(links)]; // Dedupe
}

function pathMatchesPrefix(href, prefix) {
return href === prefix || href.startsWith(`${prefix}/`);
}

function isDisallowedLink(href, disallowed, exceptions) {
const isDisallowed = disallowed.some(prefix => pathMatchesPrefix(href, prefix));
const isExcepted = exceptions.some(prefix => pathMatchesPrefix(href, prefix));
return isDisallowed && !isExcepted;
}

// Main validation
function main() {
console.log('🔗 R4 — Internal Link Integrity Gate\n');

const navMap = loadNavigationMap();
const disallowed = navMap.disallowed_routes || [];
const exceptions = navMap.disallowed_route_exceptions || [];
const internalLinks = collectInternalLinks(navMap);

let failures = [];
Expand All @@ -94,7 +105,7 @@ function main() {

for (const href of internalLinks) {
// Check disallowed
if (disallowed.some(d => href.startsWith(d))) {
if (isDisallowedLink(href, disallowed, exceptions)) {
failures.push({ href, reason: 'Links to disallowed path' });
continue;
}
Expand Down
6 changes: 6 additions & 0 deletions scripts/ci/toplevel-whitelist-gate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,23 @@ const DIRECTORY_WHITELIST = [

// Data sources
'data',
'content',
'export',
'fixtures',
'schemas',
'test-vectors',

// Governance & releases
'audit',
'governance',
'releases',
'adjudication',
'plans',
'reverification',
'reports',

// Tools & utilities
'runners',
'scripts',
'tools',
'verifier',
Expand Down
Loading
Loading