archctx-contracts 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/fixtures/boundary/agent-job-expired.json +33 -0
  2. package/fixtures/boundary/architecture-event-extension.json +41 -0
  3. package/fixtures/boundary/architecture-node-extension.json +13 -0
  4. package/fixtures/boundary/attestation-v2-error.json +43 -0
  5. package/fixtures/boundary/check-delivery-dead-letter.json +14 -0
  6. package/fixtures/boundary/evidence-binding-context-only.json +20 -0
  7. package/fixtures/boundary/practice-disabled-overlay.json +59 -0
  8. package/fixtures/boundary/recommendation-deferred.json +19 -0
  9. package/fixtures/boundary/review-challenge-v2-organization.json +15 -0
  10. package/fixtures/boundary/runner-identity-organization-scope.json +16 -0
  11. package/fixtures/invalid/adapter-fidelity-reverse-sync.json +9 -0
  12. package/fixtures/invalid/agent-job-direct-mutation.json +32 -0
  13. package/fixtures/invalid/architecture-event-source-body-field.json +39 -0
  14. package/fixtures/invalid/architecture-snapshot-unknown-mode.json +29 -0
  15. package/fixtures/invalid/attestation-v2-finding-field.json +39 -0
  16. package/fixtures/invalid/check-delivery-legacy-check-name.json +14 -0
  17. package/fixtures/invalid/cloud-egress-envelope-private-field.json +12 -0
  18. package/fixtures/invalid/compatibility-illegal-reason.json +17 -0
  19. package/fixtures/invalid/evidence-binding-summary-substring-authority.json +17 -0
  20. package/fixtures/invalid/evidence-item-source-body-field.json +27 -0
  21. package/fixtures/invalid/explorer-projection-write-field.json +21 -0
  22. package/fixtures/invalid/investigation-report-direct-mutation.json +38 -0
  23. package/fixtures/invalid/investigation-report-missing-proposed-delta.json +19 -0
  24. package/fixtures/invalid/node-unknown-field.json +10 -0
  25. package/fixtures/invalid/notification-event-code-field.json +11 -0
  26. package/fixtures/invalid/practice-policy-empty-test-evidence.json +15 -0
  27. package/fixtures/invalid/practice-policy-negative-recommendation-budget.json +10 -0
  28. package/fixtures/invalid/practice-unknown-field.json +56 -0
  29. package/fixtures/invalid/projection-target-invalid-ownership.json +18 -0
  30. package/fixtures/invalid/recommendation-feedback-implicit-acceptance.json +29 -0
  31. package/fixtures/invalid/recommendation-run-raw-input-field.json +33 -0
  32. package/fixtures/invalid/recommendation-source-body-field.json +17 -0
  33. package/fixtures/invalid/review-challenge-v2-private-field.json +16 -0
  34. package/fixtures/valid/adapter-fidelity.json +9 -0
  35. package/fixtures/valid/agent-job.json +33 -0
  36. package/fixtures/valid/architecture-candidate-delta-policy.json +45 -0
  37. package/fixtures/valid/architecture-candidate-delta.json +188 -0
  38. package/fixtures/valid/architecture-event.json +39 -0
  39. package/fixtures/valid/architecture-intervention.json +36 -0
  40. package/fixtures/valid/architecture-node.json +25 -0
  41. package/fixtures/valid/architecture-relation.json +14 -0
  42. package/fixtures/valid/architecture-snapshot.json +31 -0
  43. package/fixtures/valid/architecture-subject-selector.json +9 -0
  44. package/fixtures/valid/attestation-v2.json +38 -0
  45. package/fixtures/valid/attestation.json +25 -0
  46. package/fixtures/valid/changeset.json +30 -0
  47. package/fixtures/valid/chatgpt-ga-tool.json +9 -0
  48. package/fixtures/valid/check-delivery.json +14 -0
  49. package/fixtures/valid/cloud-egress-envelope.json +11 -0
  50. package/fixtures/valid/compatibility-contract.json +19 -0
  51. package/fixtures/valid/constraint.json +22 -0
  52. package/fixtures/valid/cross-repo-relation.json +23 -0
  53. package/fixtures/valid/device-identity.json +10 -0
  54. package/fixtures/valid/entitlement.json +12 -0
  55. package/fixtures/valid/evidence-binding.json +17 -0
  56. package/fixtures/valid/evidence-item.json +29 -0
  57. package/fixtures/valid/explorer-projection.json +53 -0
  58. package/fixtures/valid/explorer-service.json +11 -0
  59. package/fixtures/valid/external-document-resource.json +29 -0
  60. package/fixtures/valid/governance-key-status.json +11 -0
  61. package/fixtures/valid/investigation-report.json +38 -0
  62. package/fixtures/valid/landscape.json +36 -0
  63. package/fixtures/valid/likec4-mapping.json +14 -0
  64. package/fixtures/valid/notification-event.json +10 -0
  65. package/fixtures/valid/notification-provider.json +12 -0
  66. package/fixtures/valid/org-runner-identity.json +10 -0
  67. package/fixtures/valid/practice-catalog-manifest.json +16 -0
  68. package/fixtures/valid/practice-check-result.json +17 -0
  69. package/fixtures/valid/practice-checkpoint.json +94 -0
  70. package/fixtures/valid/practice-guidance.json +42 -0
  71. package/fixtures/valid/practice-match.json +23 -0
  72. package/fixtures/valid/practice-policy.json +33 -0
  73. package/fixtures/valid/practice-profile.json +22 -0
  74. package/fixtures/valid/practice-source.json +19 -0
  75. package/fixtures/valid/practice-waiver.json +14 -0
  76. package/fixtures/valid/practice.json +93 -0
  77. package/fixtures/valid/product-version-manifest.json +51 -0
  78. package/fixtures/valid/projection-target.json +18 -0
  79. package/fixtures/valid/recommendation-feedback.json +29 -0
  80. package/fixtures/valid/recommendation-run.json +33 -0
  81. package/fixtures/valid/recommendation.json +17 -0
  82. package/fixtures/valid/retrieval-config.json +20 -0
  83. package/fixtures/valid/retrieval-decision.json +26 -0
  84. package/fixtures/valid/retrieval-eval.json +14 -0
  85. package/fixtures/valid/review-challenge-v2.json +15 -0
  86. package/fixtures/valid/review-result.json +32 -0
  87. package/fixtures/valid/runner-identity.json +13 -0
  88. package/fixtures/valid/structurizr-mapping.json +15 -0
  89. package/fixtures/valid/task-context.json +23 -0
  90. package/package.json +17 -0
  91. package/src/control-plane-routes.ts +35 -0
  92. package/src/external-docs.ts +137 -0
  93. package/src/github-governance.ts +850 -0
  94. package/src/index.ts +9 -0
  95. package/src/ledger.ts +649 -0
  96. package/src/ports.ts +385 -0
  97. package/src/practices.ts +433 -0
  98. package/src/product-version.ts +108 -0
  99. package/src/schema.ts +145 -0
  100. package/src/validator.ts +95 -0
@@ -0,0 +1,95 @@
1
+ import type { Json } from "./schema";
2
+
3
+ export interface ValidationIssue {
4
+ path: string;
5
+ message: string;
6
+ }
7
+
8
+ export interface ValidationResult {
9
+ valid: boolean;
10
+ issues: ValidationIssue[];
11
+ }
12
+
13
+ type JsonSchema = {
14
+ type?: string | string[];
15
+ const?: Json;
16
+ enum?: Json[];
17
+ pattern?: string;
18
+ required?: string[];
19
+ properties?: Record<string, JsonSchema>;
20
+ items?: JsonSchema;
21
+ oneOf?: JsonSchema[];
22
+ additionalProperties?: boolean | JsonSchema;
23
+ minItems?: number;
24
+ minimum?: number;
25
+ maximum?: number;
26
+ };
27
+
28
+ export function validateJsonSchema(schema: JsonSchema, value: Json): ValidationResult {
29
+ const issues: ValidationIssue[] = [];
30
+ visit(schema, value, "$", issues);
31
+ return { valid: issues.length === 0, issues };
32
+ }
33
+
34
+ function visit(schema: JsonSchema, value: Json, path: string, issues: ValidationIssue[]): void {
35
+ if (schema.oneOf) {
36
+ const matched = schema.oneOf.filter((candidate) => {
37
+ const candidateIssues: ValidationIssue[] = [];
38
+ visit(candidate, value, path, candidateIssues);
39
+ return candidateIssues.length === 0;
40
+ }).length;
41
+ if (matched !== 1) {
42
+ issues.push({ path, message: `expected exactly one matching schema, got ${matched}` });
43
+ return;
44
+ }
45
+ }
46
+ if (schema.const !== undefined && JSON.stringify(value) !== JSON.stringify(schema.const)) {
47
+ issues.push({ path, message: `expected const ${JSON.stringify(schema.const)}` });
48
+ return;
49
+ }
50
+ if (schema.enum && !schema.enum.some((item) => JSON.stringify(item) === JSON.stringify(value))) {
51
+ issues.push({ path, message: `expected one of ${schema.enum.map(String).join(", ")}` });
52
+ }
53
+ if (schema.type && !matchesType(schema.type, value)) {
54
+ issues.push({ path, message: `expected type ${Array.isArray(schema.type) ? schema.type.join("|") : schema.type}` });
55
+ return;
56
+ }
57
+ if (typeof value === "string" && schema.pattern && !new RegExp(schema.pattern).test(value)) {
58
+ issues.push({ path, message: `does not match ${schema.pattern}` });
59
+ }
60
+ if (typeof value === "number") {
61
+ if (schema.minimum !== undefined && value < schema.minimum) issues.push({ path, message: `below minimum ${schema.minimum}` });
62
+ if (schema.maximum !== undefined && value > schema.maximum) issues.push({ path, message: `above maximum ${schema.maximum}` });
63
+ }
64
+ if (Array.isArray(value)) {
65
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
66
+ issues.push({ path, message: `expected at least ${schema.minItems} items` });
67
+ }
68
+ if (schema.items) value.forEach((item, index) => visit(schema.items!, item, `${path}[${index}]`, issues));
69
+ }
70
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
71
+ const objectValue = value as Record<string, Json>;
72
+ for (const key of schema.required ?? []) {
73
+ if (!(key in objectValue)) issues.push({ path: `${path}.${key}`, message: "required" });
74
+ }
75
+ for (const [key, child] of Object.entries(schema.properties ?? {})) {
76
+ if (key in objectValue) visit(child, objectValue[key], `${path}.${key}`, issues);
77
+ }
78
+ if (schema.additionalProperties === false && schema.properties) {
79
+ for (const key of Object.keys(objectValue)) {
80
+ if (!(key in schema.properties)) issues.push({ path: `${path}.${key}`, message: "additional property denied" });
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ function matchesType(type: string | string[], value: Json): boolean {
87
+ const allowed = Array.isArray(type) ? type : [type];
88
+ return allowed.some((candidate) => {
89
+ if (candidate === "array") return Array.isArray(value);
90
+ if (candidate === "null") return value === null;
91
+ if (candidate === "object") return value !== null && typeof value === "object" && !Array.isArray(value);
92
+ if (candidate === "integer") return Number.isInteger(value);
93
+ return typeof value === candidate;
94
+ });
95
+ }