@nomos-arc/arc 0.1.0

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 (160) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.nomos-config.json +5 -0
  3. package/CLAUDE.md +108 -0
  4. package/LICENSE +190 -0
  5. package/README.md +569 -0
  6. package/dist/cli.js +21120 -0
  7. package/docs/auth/googel_plan.yaml +1093 -0
  8. package/docs/auth/google_task.md +235 -0
  9. package/docs/auth/hardened_blueprint.yaml +1658 -0
  10. package/docs/auth/red_team_report.yaml +336 -0
  11. package/docs/auth/session_state.yaml +162 -0
  12. package/docs/certificate/cer_enhance_plan.md +605 -0
  13. package/docs/certificate/certificate_report.md +338 -0
  14. package/docs/dev_overview.md +419 -0
  15. package/docs/feature_assessment.md +156 -0
  16. package/docs/how_it_works.md +78 -0
  17. package/docs/infrastructure/map.md +867 -0
  18. package/docs/init/master_plan.md +3581 -0
  19. package/docs/init/red_team_report.md +215 -0
  20. package/docs/init/report_phase_1a.md +304 -0
  21. package/docs/integrity-gate/enhance_drift.md +703 -0
  22. package/docs/integrity-gate/overview.md +108 -0
  23. package/docs/management/manger-task.md +99 -0
  24. package/docs/management/scafffold.md +76 -0
  25. package/docs/map/ATOMIC_BLUEPRINT.md +1349 -0
  26. package/docs/map/RED_TEAM_REPORT.md +159 -0
  27. package/docs/map/map_task.md +147 -0
  28. package/docs/map/semantic_graph_task.md +792 -0
  29. package/docs/map/semantic_master_plan.md +705 -0
  30. package/docs/phase7/TEAM_RED.md +249 -0
  31. package/docs/phase7/plan.md +1682 -0
  32. package/docs/phase7/task.md +275 -0
  33. package/docs/prompts/USAGE.md +312 -0
  34. package/docs/prompts/architect.md +165 -0
  35. package/docs/prompts/executer.md +190 -0
  36. package/docs/prompts/hardener.md +190 -0
  37. package/docs/prompts/red_team.md +146 -0
  38. package/docs/verification/goveranance-overview.md +396 -0
  39. package/docs/verification/governance-overview.md +245 -0
  40. package/docs/verification/verification-arc-ar.md +560 -0
  41. package/docs/verification/verification-architecture.md +560 -0
  42. package/docs/very_next.md +52 -0
  43. package/docs/whitepaper.md +89 -0
  44. package/overview.md +1469 -0
  45. package/package.json +63 -0
  46. package/src/adapters/__tests__/git.test.ts +296 -0
  47. package/src/adapters/__tests__/stdio.test.ts +70 -0
  48. package/src/adapters/git.ts +226 -0
  49. package/src/adapters/pty.ts +159 -0
  50. package/src/adapters/stdio.ts +113 -0
  51. package/src/cli.ts +83 -0
  52. package/src/commands/apply.ts +47 -0
  53. package/src/commands/auth.ts +301 -0
  54. package/src/commands/certificate.ts +89 -0
  55. package/src/commands/discard.ts +24 -0
  56. package/src/commands/drift.ts +116 -0
  57. package/src/commands/index.ts +78 -0
  58. package/src/commands/init.ts +121 -0
  59. package/src/commands/list.ts +75 -0
  60. package/src/commands/map.ts +55 -0
  61. package/src/commands/plan.ts +30 -0
  62. package/src/commands/review.ts +58 -0
  63. package/src/commands/run.ts +63 -0
  64. package/src/commands/search.ts +147 -0
  65. package/src/commands/show.ts +63 -0
  66. package/src/commands/status.ts +59 -0
  67. package/src/core/__tests__/budget.test.ts +213 -0
  68. package/src/core/__tests__/certificate.test.ts +385 -0
  69. package/src/core/__tests__/config.test.ts +191 -0
  70. package/src/core/__tests__/preflight.test.ts +24 -0
  71. package/src/core/__tests__/prompt.test.ts +358 -0
  72. package/src/core/__tests__/review.test.ts +161 -0
  73. package/src/core/__tests__/state.test.ts +362 -0
  74. package/src/core/auth/__tests__/manager.test.ts +166 -0
  75. package/src/core/auth/__tests__/server.test.ts +220 -0
  76. package/src/core/auth/gcp-projects.ts +160 -0
  77. package/src/core/auth/manager.ts +114 -0
  78. package/src/core/auth/server.ts +141 -0
  79. package/src/core/budget.ts +119 -0
  80. package/src/core/certificate.ts +502 -0
  81. package/src/core/config.ts +212 -0
  82. package/src/core/errors.ts +54 -0
  83. package/src/core/factory.ts +49 -0
  84. package/src/core/graph/__tests__/builder.test.ts +272 -0
  85. package/src/core/graph/__tests__/contract-writer.test.ts +175 -0
  86. package/src/core/graph/__tests__/enricher.test.ts +299 -0
  87. package/src/core/graph/__tests__/parser.test.ts +200 -0
  88. package/src/core/graph/__tests__/pipeline.test.ts +202 -0
  89. package/src/core/graph/__tests__/renderer.test.ts +128 -0
  90. package/src/core/graph/__tests__/resolver.test.ts +185 -0
  91. package/src/core/graph/__tests__/scanner.test.ts +231 -0
  92. package/src/core/graph/__tests__/show.test.ts +134 -0
  93. package/src/core/graph/builder.ts +303 -0
  94. package/src/core/graph/constraints.ts +94 -0
  95. package/src/core/graph/contract-writer.ts +93 -0
  96. package/src/core/graph/drift/__tests__/classifier.test.ts +215 -0
  97. package/src/core/graph/drift/__tests__/comparator.test.ts +335 -0
  98. package/src/core/graph/drift/__tests__/drift.test.ts +453 -0
  99. package/src/core/graph/drift/__tests__/reporter.test.ts +203 -0
  100. package/src/core/graph/drift/classifier.ts +165 -0
  101. package/src/core/graph/drift/comparator.ts +205 -0
  102. package/src/core/graph/drift/reporter.ts +77 -0
  103. package/src/core/graph/enricher.ts +251 -0
  104. package/src/core/graph/grammar-paths.ts +30 -0
  105. package/src/core/graph/html-template.ts +493 -0
  106. package/src/core/graph/map-schema.ts +137 -0
  107. package/src/core/graph/parser.ts +336 -0
  108. package/src/core/graph/pipeline.ts +209 -0
  109. package/src/core/graph/renderer.ts +92 -0
  110. package/src/core/graph/resolver.ts +195 -0
  111. package/src/core/graph/scanner.ts +145 -0
  112. package/src/core/logger.ts +46 -0
  113. package/src/core/orchestrator.ts +792 -0
  114. package/src/core/plan-file-manager.ts +66 -0
  115. package/src/core/preflight.ts +64 -0
  116. package/src/core/prompt.ts +173 -0
  117. package/src/core/review.ts +95 -0
  118. package/src/core/state.ts +294 -0
  119. package/src/core/worktree-coordinator.ts +77 -0
  120. package/src/search/__tests__/chunk-extractor.test.ts +339 -0
  121. package/src/search/__tests__/embedder-auth.test.ts +124 -0
  122. package/src/search/__tests__/embedder.test.ts +267 -0
  123. package/src/search/__tests__/graph-enricher.test.ts +178 -0
  124. package/src/search/__tests__/indexer.test.ts +518 -0
  125. package/src/search/__tests__/integration.test.ts +649 -0
  126. package/src/search/__tests__/query-engine.test.ts +334 -0
  127. package/src/search/__tests__/similarity.test.ts +78 -0
  128. package/src/search/__tests__/vector-store.test.ts +281 -0
  129. package/src/search/chunk-extractor.ts +167 -0
  130. package/src/search/embedder.ts +209 -0
  131. package/src/search/graph-enricher.ts +95 -0
  132. package/src/search/indexer.ts +483 -0
  133. package/src/search/lexical-searcher.ts +190 -0
  134. package/src/search/query-engine.ts +225 -0
  135. package/src/search/vector-store.ts +311 -0
  136. package/src/types/index.ts +572 -0
  137. package/src/utils/__tests__/ansi.test.ts +54 -0
  138. package/src/utils/__tests__/frontmatter.test.ts +79 -0
  139. package/src/utils/__tests__/sanitize.test.ts +229 -0
  140. package/src/utils/ansi.ts +19 -0
  141. package/src/utils/context.ts +44 -0
  142. package/src/utils/frontmatter.ts +27 -0
  143. package/src/utils/sanitize.ts +78 -0
  144. package/test/e2e/lifecycle.test.ts +330 -0
  145. package/test/fixtures/mock-planner-hang.ts +5 -0
  146. package/test/fixtures/mock-planner.ts +26 -0
  147. package/test/fixtures/mock-reviewer-bad.ts +8 -0
  148. package/test/fixtures/mock-reviewer-retry.ts +34 -0
  149. package/test/fixtures/mock-reviewer.ts +18 -0
  150. package/test/fixtures/sample-project/src/circular-a.ts +6 -0
  151. package/test/fixtures/sample-project/src/circular-b.ts +6 -0
  152. package/test/fixtures/sample-project/src/config.ts +15 -0
  153. package/test/fixtures/sample-project/src/main.ts +19 -0
  154. package/test/fixtures/sample-project/src/services/product-service.ts +20 -0
  155. package/test/fixtures/sample-project/src/services/user-service.ts +18 -0
  156. package/test/fixtures/sample-project/src/types.ts +14 -0
  157. package/test/fixtures/sample-project/src/utils/index.ts +14 -0
  158. package/test/fixtures/sample-project/src/utils/validate.ts +12 -0
  159. package/tsconfig.json +20 -0
  160. package/vitest.config.ts +12 -0
@@ -0,0 +1,605 @@
1
+ # Certificate Enhancement Plan — Enterprise Grade
2
+
3
+ > **Document:** `enhance_plan.md`
4
+ > **Author:** Senior Technical Architect / CEO, nomos-arc.ai
5
+ > **Date:** 2026-04-04
6
+ > **Status:** Approved for Implementation
7
+ > **Scope:** Certificate v2 — Non-Repudiation, Governance Persistence, CI/CD Enforcement, Executive Reporting
8
+
9
+ ---
10
+
11
+ ## Executive Summary
12
+
13
+ The Certificate of AI Engineering Integrity (v1) establishes tamper-evidence through hash chaining and self-sealing. This is sufficient to prove *internal consistency* but insufficient for enterprise compliance. Three critical gaps remain:
14
+
15
+ 1. **Non-Repudiation**: The certificate proves *what* happened but not *who* vouches for it. Without a digital signature bound to a developer identity, the certificate is an unsigned assertion.
16
+ 2. **Governance Persistence**: The `rules_hash` proves rules *existed* at generation time but cannot reproduce them if the original files are deleted or modified. An auditor holding only the certificate has a hash with no content to verify against.
17
+ 3. **Passive Artifact**: The certificate is generated but never enforced. Code can be merged without one. In regulated environments, an unenforced control is equivalent to no control.
18
+
19
+ Addressing these gaps transforms the certificate from a *documentation artifact* into a **cryptographic compliance gate** — the first in the AI-assisted engineering market. This positions nomos-arc.ai as the only tool that provides verifiable, enforceable, identity-bound proof of responsible AI engineering.
20
+
21
+ **Market impact**: Enterprise procurement in Banking, Healthcare, and Defense requires non-repudiation and CI/CD enforcement as baseline criteria. Without these, the certificate is a differentiator for demos but not for contracts.
22
+
23
+ ---
24
+
25
+ ## 1. Digital Signature Layer (Non-Repudiation)
26
+
27
+ ### 1.1 Problem Statement
28
+
29
+ The current `certificate_hash` proves the payload has not been modified since generation, but it does not bind the certificate to a human identity. Any process with write access to the certificate file can regenerate a valid `certificate_hash` after tampering with the content. The hash chain is tamper-evident but not tamper-proof without an external trust anchor.
30
+
31
+ ### 1.2 Design
32
+
33
+ Integrate SSH and GPG signing to produce an identity-bound signature over the `certificate_hash`. The signature block is appended to the certificate payload *after* the self-seal, creating a layered integrity model:
34
+
35
+ ```
36
+ Layer 1: chain_hash → proves history entry integrity
37
+ Layer 2: certificate_hash → proves payload integrity (self-seal)
38
+ Layer 3: signature → proves identity + non-repudiation
39
+ ```
40
+
41
+ ### 1.3 Implementation Steps
42
+
43
+ #### Step 1: Define the `SignatureBlock` schema
44
+
45
+ ```typescript
46
+ interface SignatureBlock {
47
+ signer: string; // e.g., "Ibrahim Magdy <ibrahim@nomos-arc.ai>"
48
+ method: 'ssh-ed25519' | 'ssh-rsa' | 'gpg';
49
+ key_fingerprint: string; // public key fingerprint for audit trail
50
+ signed_hash: string; // the certificate_hash that was signed
51
+ signature: string; // base64-encoded detached signature
52
+ signed_at: string; // ISO 8601
53
+ }
54
+ ```
55
+
56
+ The `SignatureBlock` is added as an optional field on `CertificatePayload`. It is *not* included in the `certificate_hash` computation — the signature signs the hash, not the payload. This preserves backward compatibility: unsigned certificates remain valid for v1 verification.
57
+
58
+ #### Step 2: Implement `arc certificate <task> --sign`
59
+
60
+ The `--sign` flag triggers the signing flow after certificate generation:
61
+
62
+ 1. **Key discovery**: Check for available signing keys in order of preference:
63
+ - `ssh-agent` (via `SSH_AUTH_SOCK`): List keys with `ssh-add -L`, select the first ed25519 key.
64
+ - GPG keyring: Execute `gpg --list-secret-keys --keyid-format=long`, use the first available key.
65
+ - Explicit key path: `--sign-key <path>` flag for environments without agent.
66
+
67
+ 2. **Signature computation**:
68
+ - Extract `certificate_hash` value (the hex string after `sha256:`).
69
+ - For SSH: Write hash to temp file, execute `ssh-keygen -Y sign -f <key> -n nomos-certificate <tempfile>`.
70
+ - For GPG: Pipe hash to `gpg --detach-sign --armor --local-user <keyid>`.
71
+
72
+ 3. **Block assembly**: Populate `SignatureBlock` with signer identity (from `git config user.name` + `git config user.email`), method, fingerprint, signature output, and timestamp.
73
+
74
+ 4. **Append to certificate**: Add `signature` field to the certificate JSON and write to disk. The `certificate_hash` is *not* recomputed — the signature is outside the seal.
75
+
76
+ #### Step 3: Implement signature verification in `--verify`
77
+
78
+ Add a 6th verification check: `signature_validity`.
79
+
80
+ - If `signature` block is absent: check is `SKIP` (not `FAIL`) — backward compatible.
81
+ - If present: verify that `signed_hash === certificate_hash`, then verify the cryptographic signature using the appropriate tool (`ssh-keygen -Y verify` or `gpg --verify`).
82
+ - Report signer identity and key fingerprint in the check detail.
83
+
84
+ #### Step 4: Key trust policy (optional, deferred)
85
+
86
+ For v2, nomos-arc.ai trusts any valid SSH/GPG signature — it proves *who* signed, not *whether they were authorized*. A future `allowed_signers` file (SSH) or trust-db (GPG) integration can restrict signing to approved identities.
87
+
88
+ ### 1.4 Security Analysis
89
+
90
+ - **Threat mitigated**: An attacker who modifies the certificate and recomputes `certificate_hash` cannot forge a valid signature without the signer's private key.
91
+ - **Key compromise**: If a signing key is compromised, the attacker can produce valid signatures. Mitigation: key rotation policy and fingerprint logging in the certificate allow post-incident audit of which certificates were signed with the compromised key.
92
+ - **Non-repudiation**: The signer cannot deny having signed the certificate — the signature is verifiable against their public key.
93
+
94
+ ---
95
+
96
+ ## 2. Governance Snapshot (Rules Persistence)
97
+
98
+ ### 2.1 Problem Statement
99
+
100
+ The current certificate stores `rules.files` (file names) and `rules.rules_hash` (SHA-256 of concatenated content). This proves that specific rules *were loaded* during the task lifecycle, but if the rule files are later modified or deleted from the repository, an auditor cannot reconstruct what was enforced. The hash becomes unverifiable against thin air.
101
+
102
+ ### 2.2 Design
103
+
104
+ Transition from "reference by hash" to "embedded context" by including a compressed summary of the active rules within the certificate. Two strategies, selected by content size:
105
+
106
+ | Strategy | Condition | Content |
107
+ |---|---|---|
108
+ | **Full embed** | Total rules content < 10 KB | Raw content of each rule file, keyed by filename |
109
+ | **Summary embed** | Total rules content >= 10 KB | First 200 lines per file + SHA-256 per file |
110
+
111
+ This ensures the certificate is self-contained for audit purposes without unbounded growth.
112
+
113
+ ### 2.3 Implementation Steps
114
+
115
+ #### Step 1: Extend the `rules` section in `CertificatePayload`
116
+
117
+ ```typescript
118
+ rules: {
119
+ files: string[];
120
+ rules_hash: string;
121
+ // NEW — v2 addition
122
+ rules_snapshot: {
123
+ strategy: 'full' | 'summary';
124
+ content: Record<string, {
125
+ hash: string; // per-file SHA-256
126
+ body: string; // full content or truncated (first 200 lines)
127
+ truncated: boolean; // true if body is not the full file
128
+ }>;
129
+ total_size_bytes: number; // original total size before any truncation
130
+ };
131
+ };
132
+ ```
133
+
134
+ #### Step 2: Populate during `generate()`
135
+
136
+ In `CertificateEngine.generate()`, after loading the task state:
137
+
138
+ 1. Read each file listed in `state.context.rules` from disk (resolve paths relative to `rules/` directory).
139
+ 2. Compute per-file SHA-256.
140
+ 3. If total content size < 10,240 bytes: embed full content, set `strategy: 'full'`.
141
+ 4. If >= 10,240 bytes: truncate each file to first 200 lines, set `strategy: 'summary'`, mark `truncated: true`.
142
+ 5. Verify that SHA-256 of concatenated *full* content matches `state.context.rules_hash` — if mismatch, warn that rules have been modified since task execution (do not block generation, but add a warning to output).
143
+
144
+ #### Step 3: Add verification check `rules_integrity`
145
+
146
+ A 7th verification check (or 6th if signature is absent):
147
+
148
+ - Recompute `rules_hash` from `rules_snapshot.content` (using full bodies only if `strategy: 'full'`).
149
+ - Compare with `rules.rules_hash`.
150
+ - If strategy is `summary` (truncated), the check can only verify per-file hashes, not the aggregate — mark as `PARTIAL`.
151
+
152
+ #### Step 4: Handle missing rule files gracefully
153
+
154
+ If a rule file listed in `state.context.rules` no longer exists on disk at certificate generation time:
155
+
156
+ - Log a warning: `Rule file "backend.md" no longer exists — embedding from state snapshot`.
157
+ - If the content is recoverable from git history (`git show HEAD:rules/backend.md`), use that.
158
+ - If not recoverable, embed `{ hash: state_hash, body: "[content unavailable — file deleted]", truncated: false }`.
159
+ - This is a **degraded** certificate — the `rules_integrity` check will note the gap.
160
+
161
+ ### 2.4 Security Analysis
162
+
163
+ - **Threat mitigated**: Post-hoc rule modification to make a non-compliant task appear compliant. With embedded rules, the certificate is self-contained evidence of what was enforced.
164
+ - **Size concern**: The 10 KB threshold prevents certificate bloat. For projects with extensive rule sets, the summary strategy preserves auditability (per-file hashes) while bounding size.
165
+
166
+ ---
167
+
168
+ ## 3. CI/CD Enforcement Gate (The "Hard Gate")
169
+
170
+ ### 3.1 Problem Statement
171
+
172
+ The certificate is currently generated on-demand and never checked. A developer can merge code without ever running `arc certificate`. In regulated environments, an unenforced control is an audit finding, not a feature.
173
+
174
+ ### 3.2 Design
175
+
176
+ A GitHub Action (`nomos-gate`) that runs as a required status check on pull requests. It performs four verifications and blocks merge if any fail:
177
+
178
+ ```
179
+ PR opened/updated
180
+
181
+ nomos-gate action
182
+ ├── 1. Certificate exists for this PR's head commit
183
+ ├── 2. chain_hash is valid
184
+ ├── 3. Digital signature is valid (if signing is required)
185
+ └── 4. base_commit matches PR head
186
+
187
+ All pass → ✅ Status check passes
188
+ Any fail → ❌ Status check fails, merge blocked
189
+ ```
190
+
191
+ ### 3.3 Implementation Steps
192
+
193
+ #### Step 1: Define the GitHub Action (`action.yml`)
194
+
195
+ ```yaml
196
+ name: 'nomos-arc Certificate Gate'
197
+ description: 'Verify AI Engineering Integrity Certificate before merge'
198
+ inputs:
199
+ certificate-path:
200
+ description: 'Path to the certificate JSON file'
201
+ required: false
202
+ default: 'tasks-management/certificates/*.certificate.json'
203
+ require-signature:
204
+ description: 'Require a valid digital signature'
205
+ required: false
206
+ default: 'false'
207
+ allowed-signers:
208
+ description: 'Path to allowed_signers file (SSH) for identity verification'
209
+ required: false
210
+ runs:
211
+ using: 'node20'
212
+ main: 'dist/gate/index.js'
213
+ ```
214
+
215
+ #### Step 2: Gate logic (`src/gate/index.ts`)
216
+
217
+ The gate action performs the following sequence:
218
+
219
+ 1. **Certificate discovery**: Glob for `*.certificate.json` files matching the configured path. If no certificate found, fail with `MISSING_CERTIFICATE`.
220
+
221
+ 2. **Parse + schema validation**: Use `CertificateEngine.parse()` to validate JSON structure. Fail with `INVALID_SCHEMA` on Zod errors.
222
+
223
+ 3. **Full verification**: Run `CertificateEngine.verify()` — all 5 (or 7 with new checks) must pass.
224
+
225
+ 4. **Commit binding**: Extract `repository.base_commit` from the certificate. Compare against the PR's head commit SHA (available via `github.event.pull_request.head.sha`). This proves the certificate was generated for *this specific code*, not a different version.
226
+
227
+ - **Matching strategy**: The certificate's `base_commit` is the commit the shadow branch forked from, while the PR's head SHA is the latest commit on the branch. The gate should verify that `base_commit` is an ancestor of the PR head commit, or that the PR's commit list includes changes from the shadow branch.
228
+ - Simplified v1: Verify that `repository.shadow_branch` matches the PR's head branch name. This is weaker but sufficient for MVP.
229
+
230
+ 5. **Signature validation** (if `require-signature: true`):
231
+ - Check that `signature` block exists in the certificate.
232
+ - Verify the cryptographic signature using `ssh-keygen -Y verify` or `gpg --verify`.
233
+ - If `allowed-signers` is provided, verify the signer is in the allowed list.
234
+
235
+ 6. **Result reporting**: Set the GitHub status check result. On failure, post a PR comment with the specific check failures for developer visibility.
236
+
237
+ #### Step 3: Output annotations
238
+
239
+ Use `@actions/core` to emit annotations:
240
+
241
+ ```typescript
242
+ core.error('Certificate chain_hash verification failed', {
243
+ file: certificatePath,
244
+ title: 'nomos-arc Certificate Gate: CHAIN_HASH_INVALID',
245
+ });
246
+ ```
247
+
248
+ #### Step 4: Configuration in consumer repos
249
+
250
+ ```yaml
251
+ # .github/workflows/nomos-gate.yml
252
+ name: nomos-arc Certificate Gate
253
+ on:
254
+ pull_request:
255
+ types: [opened, synchronize]
256
+
257
+ jobs:
258
+ verify:
259
+ runs-on: ubuntu-latest
260
+ steps:
261
+ - uses: actions/checkout@v4
262
+ - uses: nomos-arc/nomos-gate@v1
263
+ with:
264
+ require-signature: true
265
+ allowed-signers: .nomos/allowed_signers
266
+ ```
267
+
268
+ #### Step 5: Branch protection integration
269
+
270
+ Document that the consumer must add `nomos-gate` as a required status check in GitHub branch protection settings. Without this, the action runs but doesn't block.
271
+
272
+ ### 3.4 Security Analysis
273
+
274
+ - **Threat mitigated**: Merging code without a valid certificate, or using a certificate generated for a different branch/commit.
275
+ - **Bypass risk**: Repository admins can override required status checks. This is a GitHub platform limitation, not a nomos-arc.ai limitation. The certificate's immutable audit trail still records whether the gate was passed legitimately.
276
+ - **Commit binding weakness**: The MVP branch-name matching is weaker than full commit-ancestry verification. A developer could theoretically name a different branch identically. The full commit-ancestry check should be implemented in v2.1.
277
+
278
+ ---
279
+
280
+ ## 4. Human-Centric Reporting (The Executive View)
281
+
282
+ ### 4.1 Problem Statement
283
+
284
+ CTOs and auditors do not read JSON. The certificate in its current form is machine-readable but not board-ready. A compliance report must be visually professional, printable, and immediately interpretable by non-technical stakeholders.
285
+
286
+ ### 4.2 Design
287
+
288
+ Implement `arc certificate <task> --format pdf` and `--format html` that render the certificate JSON into a professional compliance report.
289
+
290
+ ### 4.3 Implementation Steps
291
+
292
+ #### Step 1: Template engine selection
293
+
294
+ Use a lightweight, zero-native-dependency approach:
295
+
296
+ | Option | Pros | Cons | Recommendation |
297
+ |---|---|---|---|
298
+ | `handlebars` + `puppeteer` | Full HTML/CSS control, PDF via Chrome headless | Puppeteer is ~400 MB | Only for environments with Chrome |
299
+ | `handlebars` + `@react-pdf/renderer` | React-based PDF, tree-shakeable | JSX dependency | Over-engineered for templates |
300
+ | **`ejs` + `html-pdf-node`** | Lightweight, template-based, Chromium-free | Less CSS control | **Recommended for CLI** |
301
+ | `handlebars` + raw HTML export | Zero new deps for HTML; PDF deferred | No PDF without browser | **Recommended for v2 MVP** |
302
+
303
+ **Decision**: For v2, implement HTML export using `handlebars` (single dependency, 72 KB). PDF generation via `--format pdf` deferred to v2.1 with `puppeteer` as an optional peer dependency — users who need PDF install it; the CLI stays lightweight.
304
+
305
+ #### Step 2: Report template structure
306
+
307
+ ```
308
+ ┌──────────────────────────────────────────────────┐
309
+ │ nomos-arc.ai — Certificate of AI Engineering │
310
+ │ Integrity │
311
+ │ │
312
+ │ ┌────────────────────────────────────────────┐ │
313
+ │ │ VERIFICATION STATUS: ✅ VALID │ │
314
+ │ │ Certificate Hash: sha256:2c624232c... │ │
315
+ │ │ Generated: 2026-04-04T12:00:00Z │ │
316
+ │ │ Signed by: Ibrahim Magdy (ssh-ed25519) │ │
317
+ │ └────────────────────────────────────────────┘ │
318
+ │ │
319
+ │ TASK SUMMARY │
320
+ │ ─────────────────────────────────────────────── │
321
+ │ Task ID: implement-auth-middleware │
322
+ │ Status: approved │
323
+ │ Iterations: 2 │
324
+ │ Final Score: 0.92 / 1.00 │
325
+ │ Approval: score_threshold │
326
+ │ │
327
+ │ REVIEW TRAIL │
328
+ │ ─────────────────────────────────────────────── │
329
+ │ Version 1: │
330
+ │ Planning: claude (supervised) │
331
+ │ Review: codex → 0.65 (1 high-severity issue) │
332
+ │ Version 2: │
333
+ │ Planning: claude (supervised) │
334
+ │ Review: codex → 0.92 (0 issues) │
335
+ │ │
336
+ │ GOVERNANCE │
337
+ │ ─────────────────────────────────────────────── │
338
+ │ Rules enforced: global.md, backend.md │
339
+ │ Rules hash: sha256:9f86d081884c... │
340
+ │ │
341
+ │ INTEGRITY │
342
+ │ ─────────────────────────────────────────────── │
343
+ │ Chain algorithm: sha256-sequential │
344
+ │ Chain hash: sha256:7d865e959b24... │
345
+ │ Entries: 4 │
346
+ │ │
347
+ │ BUDGET │
348
+ │ ─────────────────────────────────────────────── │
349
+ │ Total tokens: 8,600 │
350
+ │ Estimated cost: $0.02 │
351
+ │ │
352
+ │ ─────────────────────────────────────────────── │
353
+ │ Generated by nomos-arc@0.1.0 │
354
+ │ Verify: arc certificate <task> --verify │
355
+ └──────────────────────────────────────────────────┘
356
+ ```
357
+
358
+ #### Step 3: Implement the rendering pipeline
359
+
360
+ 1. Add `CertificateRenderer` class in `src/core/certificate-renderer.ts`.
361
+ 2. Method `renderHTML(certificate: CertificatePayload, verificationResult?: VerificationResult): string`.
362
+ 3. Load the Handlebars template from `src/templates/certificate-report.hbs`.
363
+ 4. Inject certificate data, computed fields (formatted dates, score percentages, issue counts), and optional verification result.
364
+ 5. Return the compiled HTML string.
365
+
366
+ #### Step 4: Wire into CLI
367
+
368
+ Extend the `--format` flag to accept `html`:
369
+
370
+ ```typescript
371
+ if (opts.format === 'html') {
372
+ const renderer = new CertificateRenderer();
373
+ const result = engine.verify(certificate);
374
+ const html = renderer.renderHTML(certificate, result);
375
+ const htmlPath = certPath.replace('.json', '.html');
376
+ fs.writeFileSync(htmlPath, html, 'utf-8');
377
+ console.log(`Report saved to: ${htmlPath}`);
378
+ }
379
+ ```
380
+
381
+ #### Step 5: CSS for print
382
+
383
+ Include a `@media print` stylesheet in the HTML template for direct browser-to-PDF printing. This provides a zero-dependency PDF path: open HTML in browser, print to PDF.
384
+
385
+ ---
386
+
387
+ ## 5. Schema Updates
388
+
389
+ ### 5.1 `CertificatePayload` interface changes (`src/types/index.ts`)
390
+
391
+ ```typescript
392
+ export interface CertificatePayload {
393
+ // Envelope
394
+ certificate_version: 1 | 2; // CHANGED: support v2
395
+ generated_at: string;
396
+ generator: string;
397
+
398
+ // Subject (unchanged)
399
+ task_id: string;
400
+ task_status: TaskStatus;
401
+ created_at: string;
402
+ completed_at: string;
403
+
404
+ // Repository provenance (unchanged)
405
+ repository: {
406
+ base_commit: string;
407
+ shadow_branch: string;
408
+ branch_status: 'active' | 'merged' | 'discarded';
409
+ };
410
+
411
+ // AI provenance (unchanged)
412
+ models: {
413
+ planner: string;
414
+ reviewer: string;
415
+ };
416
+
417
+ // Governance — EXTENDED
418
+ rules: {
419
+ files: string[];
420
+ rules_hash: string;
421
+ rules_snapshot?: { // NEW — v2
422
+ strategy: 'full' | 'summary';
423
+ content: Record<string, {
424
+ hash: string;
425
+ body: string;
426
+ truncated: boolean;
427
+ }>;
428
+ total_size_bytes: number;
429
+ };
430
+ };
431
+
432
+ // Review trail (unchanged)
433
+ iterations: CertificateIteration[];
434
+ final_review: {
435
+ score: number;
436
+ summary: string;
437
+ issues: ReviewIssue[];
438
+ approval_reason: 'score_threshold' | 'max_iterations_reached';
439
+ };
440
+
441
+ // Resources (unchanged)
442
+ budget: {
443
+ total_tokens: number;
444
+ estimated_cost_usd: number;
445
+ token_breakdown: { input_tokens: number; output_tokens: number };
446
+ };
447
+
448
+ // Integrity (unchanged)
449
+ integrity: {
450
+ chain_hash: string;
451
+ entry_hashes: string[];
452
+ canonical_entries: string[];
453
+ chain_algorithm: 'sha256-sequential';
454
+ };
455
+
456
+ // Self-seal (unchanged)
457
+ certificate_hash: string;
458
+
459
+ // Digital signature — NEW (v2, optional)
460
+ signature?: SignatureBlock;
461
+ }
462
+
463
+ // NEW interface
464
+ export interface SignatureBlock {
465
+ signer: string;
466
+ method: 'ssh-ed25519' | 'ssh-rsa' | 'gpg';
467
+ key_fingerprint: string;
468
+ signed_hash: string;
469
+ signature: string;
470
+ signed_at: string;
471
+ }
472
+ ```
473
+
474
+ ### 5.2 Zod schema updates (`src/core/certificate.ts`)
475
+
476
+ - Add `SignatureBlockSchema` as an optional field on `CertificatePayloadSchema`.
477
+ - Add `RulesSnapshotSchema` within the `rules` object.
478
+ - Update `certificate_version` from `z.literal(1)` to `z.union([z.literal(1), z.literal(2)])`.
479
+ - All new fields are optional to maintain backward compatibility with v1 certificates.
480
+
481
+ ### 5.3 Verification checks update
482
+
483
+ | # | Check | v1 | v2 |
484
+ |---|---|---|---|
485
+ | 1 | `status_validity` | Yes | Yes |
486
+ | 2 | `review_completeness` | Yes | Yes |
487
+ | 3 | `certificate_hash` | Yes | Yes |
488
+ | 4 | `chain_hash` | Yes | Yes |
489
+ | 5 | `entry_hash_consistency` | Yes | Yes |
490
+ | 6 | `signature_validity` | - | Yes (SKIP if unsigned) |
491
+ | 7 | `rules_integrity` | - | Yes (PARTIAL if summary) |
492
+
493
+ ---
494
+
495
+ ## 6. Security Analysis
496
+
497
+ ### 6.1 Threat Model
498
+
499
+ | Threat | Pre-Enhancement | Post-Enhancement |
500
+ |---|---|---|
501
+ | **Payload tampering** (modify score after generation) | Detected via `certificate_hash` | Detected via `certificate_hash` + signature prevents re-seal |
502
+ | **History rewriting** (alter iteration data) | Detected via `chain_hash` | Detected via `chain_hash` + signature prevents re-seal |
503
+ | **Identity spoofing** (claim someone else generated it) | Not addressed | Signature binds to SSH/GPG key identity |
504
+ | **Rule modification** (change rules after task completion) | Detected via `rules_hash` but unverifiable without originals | Full rules embedded — self-contained verification |
505
+ | **Certificate absence** (merge without certificate) | Not enforced | CI/CD gate blocks merge |
506
+ | **Certificate reuse** (use cert from different branch) | Not detected | `base_commit` binding in CI/CD gate |
507
+ | **Shadow AI** (using unapproved AI tools outside nomos-arc.ai) | Not addressed | Certificate absence in CI/CD blocks unauthorized AI work from merging without a process record |
508
+
509
+ ### 6.2 Residual Risks
510
+
511
+ 1. **Key compromise**: A compromised signing key allows forgery. Mitigation: key fingerprint logging enables post-incident audit.
512
+ 2. **Admin override**: GitHub admins can bypass required status checks. Mitigation: the certificate audit trail persists independently.
513
+ 3. **Offline tampering**: A developer with repo access can craft a fake certificate with valid structure. Mitigation: digital signature makes this computationally infeasible without the private key.
514
+ 4. **Rule file unavailability**: If rule files are deleted before certificate generation, the snapshot will be incomplete. Mitigation: attempt git history recovery; flag as degraded.
515
+
516
+ ---
517
+
518
+ ## 7. Success Metrics
519
+
520
+ ### 7.1 Definition: Valid Enterprise Certificate
521
+
522
+ A certificate is "Enterprise Valid" when ALL of the following hold:
523
+
524
+ | Criterion | Verification Method |
525
+ |---|---|
526
+ | Task status is `approved` or `merged` | `status_validity` check |
527
+ | Final review exists with score and summary | `review_completeness` check |
528
+ | Payload has not been modified since generation | `certificate_hash` check |
529
+ | History entries have not been tampered with | `chain_hash` check |
530
+ | Entry hashes are consistent across data structures | `entry_hash_consistency` check |
531
+ | Certificate is signed by an identified developer | `signature_validity` check |
532
+ | Governance rules are embedded and hash-consistent | `rules_integrity` check |
533
+ | Certificate's base_commit is ancestor of merge target | CI/CD gate `commit_binding` check |
534
+
535
+ ### 7.2 Implementation Success Criteria
536
+
537
+ | Metric | Target |
538
+ |---|---|
539
+ | All existing 26 tests continue to pass (backward compat) | 100% |
540
+ | New tests for signature, rules snapshot, and gate logic | >= 30 additional tests |
541
+ | v1 certificates verify correctly under v2 engine | Yes |
542
+ | v2 certificates with signature fail verification if tampered | Yes |
543
+ | CI/CD gate blocks merge when certificate is missing | Yes |
544
+ | CI/CD gate blocks merge when signature is invalid | Yes (when `require-signature: true`) |
545
+ | HTML report renders correctly for all certificate versions | Yes |
546
+ | No new runtime dependencies for core certificate engine | Yes (signature uses system SSH/GPG) |
547
+ | Single new dependency for HTML rendering (`handlebars`) | Yes |
548
+
549
+ ---
550
+
551
+ ## 8. Implementation Priority and Sequencing
552
+
553
+ ```
554
+ Phase 2a (Week 1-2): Governance Snapshot
555
+ └── Lowest risk, highest audit value, no external dependencies
556
+ ├── Extend CertificatePayload schema
557
+ ├── Implement rules reading + embedding in generate()
558
+ ├── Add rules_integrity verification check
559
+ └── Tests: snapshot strategies, truncation, missing files
560
+
561
+ Phase 2b (Week 2-3): Digital Signature Layer
562
+ └── Requires system SSH/GPG — integration testing needed
563
+ ├── Implement SignatureBlock and --sign flag
564
+ ├── SSH signing via ssh-keygen
565
+ ├── GPG signing via gpg CLI
566
+ ├── Add signature_validity verification check
567
+ └── Tests: sign/verify round-trip, tampered signature, missing key
568
+
569
+ Phase 2c (Week 3-4): CI/CD Enforcement Gate
570
+ └── Depends on 2a + 2b for full gate logic
571
+ ├── Create GitHub Action (nomos-gate)
572
+ ├── Implement certificate discovery + verification
573
+ ├── Implement commit binding check
574
+ ├── Integration tests with mock GitHub context
575
+ └── Documentation: consumer repo setup
576
+
577
+ Phase 2d (Week 4): Executive Reporting
578
+ └── Independent of 2a-2c, can be parallelized
579
+ ├── Add handlebars dependency
580
+ ├── Create HTML template
581
+ ├── Implement CertificateRenderer
582
+ ├── Wire --format html into CLI
583
+ └── Tests: rendering with all certificate variants
584
+ ```
585
+
586
+ ---
587
+
588
+ ## 9. Conclusion
589
+
590
+ These four enhancements transform the Certificate from a proof-of-concept into enterprise compliance infrastructure. The sequencing prioritizes audit value (governance snapshot) before cryptographic complexity (signatures) before enforcement (CI/CD gate), with reporting parallelized independently.
591
+
592
+ Upon completion, nomos-arc.ai will be the only AI engineering tool that provides:
593
+ - **Identity-bound** proof of responsible AI usage (signature)
594
+ - **Self-contained** governance evidence (rules snapshot)
595
+ - **Enforced** compliance gates (CI/CD action)
596
+ - **Board-ready** reporting (HTML/PDF export)
597
+
598
+ The certificate becomes the artifact that closes the deal in enterprise procurement.
599
+
600
+ ```
601
+ arc certificate <task> --sign → The signed proof.
602
+ arc certificate <task> --verify → The full verification.
603
+ arc certificate <task> --format html → The executive report.
604
+ nomos-gate (GitHub Action) → The hard gate.
605
+ ```