@nforma.ai/nforma 0.2.1 → 0.29.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 (193) hide show
  1. package/README.md +2 -2
  2. package/agents/{qgsd-codebase-mapper.md → nf-codebase-mapper.md} +1 -1
  3. package/agents/{qgsd-debugger.md → nf-debugger.md} +3 -3
  4. package/agents/{qgsd-executor.md → nf-executor.md} +14 -14
  5. package/agents/{qgsd-integration-checker.md → nf-integration-checker.md} +1 -1
  6. package/agents/{qgsd-phase-researcher.md → nf-phase-researcher.md} +6 -6
  7. package/agents/{qgsd-plan-checker.md → nf-plan-checker.md} +9 -9
  8. package/agents/{qgsd-planner.md → nf-planner.md} +9 -9
  9. package/agents/{qgsd-project-researcher.md → nf-project-researcher.md} +2 -2
  10. package/agents/{qgsd-quorum-orchestrator.md → nf-quorum-orchestrator.md} +33 -33
  11. package/agents/{qgsd-quorum-slot-worker.md → nf-quorum-slot-worker.md} +3 -3
  12. package/agents/{qgsd-quorum-synthesizer.md → nf-quorum-synthesizer.md} +3 -3
  13. package/agents/{qgsd-quorum-test-worker.md → nf-quorum-test-worker.md} +1 -1
  14. package/agents/{qgsd-quorum-worker.md → nf-quorum-worker.md} +6 -6
  15. package/agents/{qgsd-research-synthesizer.md → nf-research-synthesizer.md} +5 -5
  16. package/agents/{qgsd-roadmapper.md → nf-roadmapper.md} +3 -3
  17. package/agents/{qgsd-verifier.md → nf-verifier.md} +8 -8
  18. package/bin/accept-debug-invariant.cjs +2 -2
  19. package/bin/account-manager.cjs +10 -10
  20. package/bin/aggregate-requirements.cjs +1 -1
  21. package/bin/analyze-assumptions.cjs +3 -3
  22. package/bin/analyze-state-space.cjs +14 -14
  23. package/bin/assumption-register.cjs +146 -0
  24. package/bin/attribute-trace-divergence.cjs +1 -1
  25. package/bin/auth-drivers/gh-cli.cjs +1 -1
  26. package/bin/auth-drivers/pool.cjs +1 -1
  27. package/bin/autoClosePtoF.cjs +3 -3
  28. package/bin/budget-tracker.cjs +77 -0
  29. package/bin/build-layer-manifest.cjs +153 -0
  30. package/bin/call-quorum-slot.cjs +3 -3
  31. package/bin/ccr-secure-config.cjs +5 -5
  32. package/bin/check-bundled-sdks.cjs +1 -1
  33. package/bin/check-mcp-health.cjs +1 -1
  34. package/bin/check-provider-health.cjs +6 -6
  35. package/bin/check-spec-sync.cjs +26 -26
  36. package/bin/check-trace-schema-drift.cjs +5 -5
  37. package/bin/conformance-schema.cjs +2 -2
  38. package/bin/cross-layer-dashboard.cjs +297 -0
  39. package/bin/design-impact.cjs +377 -0
  40. package/bin/detect-coverage-gaps.cjs +7 -7
  41. package/bin/failure-mode-catalog.cjs +227 -0
  42. package/bin/failure-taxonomy.cjs +177 -0
  43. package/bin/formal-scope-scan.cjs +179 -0
  44. package/bin/gate-a-grounding.cjs +334 -0
  45. package/bin/gate-b-abstraction.cjs +243 -0
  46. package/bin/gate-c-validation.cjs +166 -0
  47. package/bin/generate-formal-specs.cjs +17 -17
  48. package/bin/generate-petri-net.cjs +3 -3
  49. package/bin/generate-tla-cfg.cjs +5 -5
  50. package/bin/git-heatmap.cjs +571 -0
  51. package/bin/harness-diagnostic.cjs +326 -0
  52. package/bin/hazard-model.cjs +261 -0
  53. package/bin/install-formal-tools.cjs +1 -1
  54. package/bin/install.js +184 -139
  55. package/bin/instrumentation-map.cjs +178 -0
  56. package/bin/invariant-catalog.cjs +437 -0
  57. package/bin/issue-classifier.cjs +2 -2
  58. package/bin/load-baseline-requirements.cjs +4 -4
  59. package/bin/manage-agents-core.cjs +32 -32
  60. package/bin/migrate-to-slots.cjs +39 -39
  61. package/bin/mismatch-register.cjs +217 -0
  62. package/bin/nForma.cjs +176 -81
  63. package/bin/{qgsd-solve.cjs → nf-solve.cjs} +327 -14
  64. package/bin/observe-config.cjs +8 -0
  65. package/bin/observe-debt-writer.cjs +1 -1
  66. package/bin/observe-handler-deps.cjs +356 -0
  67. package/bin/observe-handler-grafana.cjs +2 -17
  68. package/bin/observe-handler-internal.cjs +5 -5
  69. package/bin/observe-handler-logstash.cjs +2 -17
  70. package/bin/observe-handler-prometheus.cjs +2 -17
  71. package/bin/observe-handler-upstream.cjs +251 -0
  72. package/bin/observe-handlers.cjs +12 -33
  73. package/bin/observe-render.cjs +68 -22
  74. package/bin/observe-utils.cjs +37 -0
  75. package/bin/observed-fsm.cjs +324 -0
  76. package/bin/planning-paths.cjs +6 -0
  77. package/bin/polyrepo.cjs +1 -1
  78. package/bin/probe-quorum-slots.cjs +1 -1
  79. package/bin/promote-gate-maturity.cjs +274 -0
  80. package/bin/promote-model.cjs +1 -1
  81. package/bin/propose-debug-invariants.cjs +1 -1
  82. package/bin/quorum-cache.cjs +144 -0
  83. package/bin/quorum-consensus-gate.cjs +1 -1
  84. package/bin/quorum-preflight.cjs +89 -0
  85. package/bin/quorum-slot-dispatch.cjs +6 -6
  86. package/bin/requirements-core.cjs +1 -1
  87. package/bin/review-mcp-logs.cjs +1 -1
  88. package/bin/risk-heatmap.cjs +151 -0
  89. package/bin/run-account-manager-tlc.cjs +4 -4
  90. package/bin/run-account-pool-alloy.cjs +2 -2
  91. package/bin/run-alloy.cjs +2 -2
  92. package/bin/run-audit-alloy.cjs +2 -2
  93. package/bin/run-breaker-tlc.cjs +3 -3
  94. package/bin/run-formal-check.cjs +9 -9
  95. package/bin/run-formal-verify.cjs +30 -9
  96. package/bin/run-installer-alloy.cjs +2 -2
  97. package/bin/run-oscillation-tlc.cjs +4 -4
  98. package/bin/run-phase-tlc.cjs +1 -1
  99. package/bin/run-protocol-tlc.cjs +4 -4
  100. package/bin/run-quorum-composition-alloy.cjs +2 -2
  101. package/bin/run-sensitivity-sweep.cjs +2 -2
  102. package/bin/run-stop-hook-tlc.cjs +3 -3
  103. package/bin/run-tlc.cjs +21 -21
  104. package/bin/run-transcript-alloy.cjs +2 -2
  105. package/bin/secrets.cjs +5 -5
  106. package/bin/security-sweep.cjs +238 -0
  107. package/bin/sensitivity-report.cjs +3 -3
  108. package/bin/set-secret.cjs +5 -5
  109. package/bin/setup-telemetry-cron.sh +3 -3
  110. package/bin/stall-detector.cjs +126 -0
  111. package/bin/state-candidates.cjs +206 -0
  112. package/bin/sync-baseline-requirements.cjs +1 -1
  113. package/bin/telemetry-collector.cjs +1 -1
  114. package/bin/test-changed.cjs +111 -0
  115. package/bin/test-recipe-gen.cjs +250 -0
  116. package/bin/trace-corpus-stats.cjs +211 -0
  117. package/bin/unified-mcp-server.mjs +3 -3
  118. package/bin/update-scoreboard.cjs +1 -1
  119. package/bin/validate-memory.cjs +2 -2
  120. package/bin/validate-traces.cjs +10 -10
  121. package/bin/verify-quorum-health.cjs +66 -5
  122. package/bin/xstate-to-tla.cjs +4 -4
  123. package/bin/xstate-trace-walker.cjs +3 -3
  124. package/commands/{qgsd → nf}/add-phase.md +3 -3
  125. package/commands/{qgsd → nf}/add-requirement.md +3 -3
  126. package/commands/{qgsd → nf}/add-todo.md +3 -3
  127. package/commands/{qgsd → nf}/audit-milestone.md +4 -4
  128. package/commands/{qgsd → nf}/check-todos.md +3 -3
  129. package/commands/{qgsd → nf}/cleanup.md +3 -3
  130. package/commands/{qgsd → nf}/close-formal-gaps.md +2 -2
  131. package/commands/{qgsd → nf}/complete-milestone.md +9 -9
  132. package/commands/{qgsd → nf}/debug.md +9 -9
  133. package/commands/{qgsd → nf}/discuss-phase.md +3 -3
  134. package/commands/{qgsd → nf}/execute-phase.md +15 -15
  135. package/commands/{qgsd → nf}/fix-tests.md +3 -3
  136. package/commands/{qgsd → nf}/formal-test-sync.md +1 -1
  137. package/commands/{qgsd → nf}/health.md +3 -3
  138. package/commands/{qgsd → nf}/help.md +3 -3
  139. package/commands/{qgsd → nf}/insert-phase.md +3 -3
  140. package/commands/nf/join-discord.md +18 -0
  141. package/commands/{qgsd → nf}/list-phase-assumptions.md +2 -2
  142. package/commands/{qgsd → nf}/map-codebase.md +7 -7
  143. package/commands/{qgsd → nf}/map-requirements.md +3 -3
  144. package/commands/{qgsd → nf}/mcp-restart.md +3 -3
  145. package/commands/{qgsd → nf}/mcp-set-model.md +8 -8
  146. package/commands/{qgsd → nf}/mcp-setup.md +63 -63
  147. package/commands/{qgsd → nf}/mcp-status.md +3 -3
  148. package/commands/{qgsd → nf}/mcp-update.md +7 -7
  149. package/commands/{qgsd → nf}/new-milestone.md +8 -8
  150. package/commands/{qgsd → nf}/new-project.md +8 -8
  151. package/commands/{qgsd → nf}/observe.md +49 -16
  152. package/commands/{qgsd → nf}/pause-work.md +3 -3
  153. package/commands/{qgsd → nf}/plan-milestone-gaps.md +5 -5
  154. package/commands/{qgsd → nf}/plan-phase.md +6 -6
  155. package/commands/{qgsd → nf}/polyrepo.md +2 -2
  156. package/commands/{qgsd → nf}/progress.md +3 -3
  157. package/commands/{qgsd → nf}/queue.md +2 -2
  158. package/commands/{qgsd → nf}/quick.md +8 -8
  159. package/commands/{qgsd → nf}/quorum-test.md +10 -10
  160. package/commands/{qgsd → nf}/quorum.md +36 -86
  161. package/commands/{qgsd → nf}/reapply-patches.md +2 -2
  162. package/commands/{qgsd → nf}/remove-phase.md +3 -3
  163. package/commands/{qgsd → nf}/research-phase.md +12 -12
  164. package/commands/{qgsd → nf}/resume-work.md +3 -3
  165. package/commands/nf/review-requirements.md +31 -0
  166. package/commands/{qgsd → nf}/set-profile.md +3 -3
  167. package/commands/{qgsd → nf}/settings.md +6 -6
  168. package/commands/{qgsd → nf}/solve.md +35 -35
  169. package/commands/{qgsd → nf}/sync-baselines.md +4 -4
  170. package/commands/{qgsd → nf}/triage.md +10 -10
  171. package/commands/{qgsd → nf}/update.md +3 -3
  172. package/commands/{qgsd → nf}/verify-work.md +5 -5
  173. package/hooks/dist/config-loader.js +188 -32
  174. package/hooks/dist/conformance-schema.cjs +2 -2
  175. package/hooks/dist/gsd-context-monitor.js +118 -13
  176. package/hooks/dist/{qgsd-check-update.js → nf-check-update.js} +5 -5
  177. package/hooks/dist/{qgsd-circuit-breaker.js → nf-circuit-breaker.js} +35 -24
  178. package/hooks/dist/{qgsd-precompact.js → nf-precompact.js} +13 -13
  179. package/hooks/dist/{qgsd-prompt.js → nf-prompt.js} +110 -33
  180. package/hooks/dist/nf-session-start.js +185 -0
  181. package/hooks/dist/{qgsd-slot-correlator.js → nf-slot-correlator.js} +13 -5
  182. package/hooks/dist/{qgsd-spec-regen.js → nf-spec-regen.js} +17 -8
  183. package/hooks/dist/{qgsd-statusline.js → nf-statusline.js} +12 -3
  184. package/hooks/dist/{qgsd-stop.js → nf-stop.js} +152 -18
  185. package/hooks/dist/{qgsd-token-collector.js → nf-token-collector.js} +12 -4
  186. package/hooks/dist/unified-mcp-server.mjs +2 -2
  187. package/package.json +6 -4
  188. package/scripts/build-hooks.js +13 -6
  189. package/scripts/secret-audit.sh +1 -1
  190. package/scripts/verify-hooks-sync.cjs +90 -0
  191. package/templates/{qgsd.json → nf.json} +4 -4
  192. package/commands/qgsd/join-discord.md +0 -18
  193. package/hooks/dist/qgsd-session-start.js +0 -122
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // bin/build-layer-manifest.cjs
4
+ // Classifies all formal models in model-registry.json into L1/L2/L3 layers
5
+ // and generates layer-manifest.json. Extends model-registry.json with
6
+ // source_layer, gate_maturity, and layer_maturity fields per model.
7
+ //
8
+ // Requirements: INTG-01, INTG-05, INTG-06
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ const ROOT = process.env.PROJECT_ROOT || path.join(__dirname, '..');
14
+ const REGISTRY_PATH = path.join(ROOT, '.planning', 'formal', 'model-registry.json');
15
+ const MANIFEST_PATH = path.join(ROOT, '.planning', 'formal', 'layer-manifest.json');
16
+ const SPEC_DIR = path.join(ROOT, '.planning', 'formal', 'spec');
17
+
18
+ const JSON_FLAG = process.argv.includes('--json');
19
+
20
+ // ── Classification rules ────────────────────────────────────────────────────
21
+
22
+ /**
23
+ * Classify a model path into L1, L2, or L3.
24
+ *
25
+ * L3 (Reasoning): formalism "tla", "alloy", "prism", "uppaal"; files in tla/, alloy/, prism/ directories
26
+ * L2 (Semantics): spec/invariants.md files; XState machine definition; assumption-gaps.md
27
+ * L1 (Evidence): formalism "trace" or "redaction"; conformance-events.jsonl; debt.json; observe-handler outputs
28
+ */
29
+ function classifyModel(modelPath) {
30
+ const normalized = modelPath.replace(/\\/g, '/');
31
+
32
+ // L3: files in tla/, alloy/, prism/ directories or with those extensions
33
+ if (/\/(tla|alloy|prism)\//.test(normalized)) return 'L3';
34
+ if (/\.(tla|als|pm)$/.test(normalized)) return 'L3';
35
+
36
+ // L2: spec/*/invariants.md, xstate machine definitions, assumption-gaps
37
+ if (/\/spec\/[^/]+\/invariants\.md$/.test(normalized)) return 'L2';
38
+ if (/xstate|machine\.js|machine\.ts/.test(normalized)) return 'L2';
39
+ if (/assumption-gaps/.test(normalized)) return 'L2';
40
+
41
+ // L1: trace, redaction, conformance-events, debt, observe-handler
42
+ if (/conformance-events/.test(normalized)) return 'L1';
43
+ if (/debt\.json/.test(normalized)) return 'L1';
44
+ if (/observe-handler/.test(normalized)) return 'L1';
45
+ if (/trace|redaction/.test(normalized)) return 'L1';
46
+
47
+ // Fallback: classify by check-result formalism if available
48
+ return 'L1'; // default to L1 (evidence)
49
+ }
50
+
51
+ /**
52
+ * Determine layer_maturity for a model.
53
+ * Level 0: ungrounded (default)
54
+ * Level 1: has L2 semantic declarations (spec invariants.md exists for related module)
55
+ */
56
+ function computeLayerMaturity(modelPath, specModules) {
57
+ const normalized = modelPath.replace(/\\/g, '/');
58
+ // Check if any spec module name appears in the model path
59
+ for (const mod of specModules) {
60
+ if (normalized.toLowerCase().includes(mod.toLowerCase())) {
61
+ return 1;
62
+ }
63
+ }
64
+ return 0;
65
+ }
66
+
67
+ // ── Main ────────────────────────────────────────────────────────────────────
68
+
69
+ function main() {
70
+ // Read registry
71
+ const registry = JSON.parse(fs.readFileSync(REGISTRY_PATH, 'utf8'));
72
+ const models = registry.models;
73
+ const modelPaths = Object.keys(models);
74
+
75
+ // Discover spec modules with invariants.md
76
+ const specModules = [];
77
+ if (fs.existsSync(SPEC_DIR)) {
78
+ for (const entry of fs.readdirSync(SPEC_DIR, { withFileTypes: true })) {
79
+ if (entry.isDirectory()) {
80
+ const invPath = path.join(SPEC_DIR, entry.name, 'invariants.md');
81
+ if (fs.existsSync(invPath)) {
82
+ specModules.push(entry.name);
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ // Classify each model and extend registry
89
+ const layers = { L1: [], L2: [], L3: [] };
90
+ const maturityDist = { 0: 0, 1: 0 };
91
+
92
+ for (const modelPath of modelPaths) {
93
+ const layer = classifyModel(modelPath);
94
+ const layerMaturity = computeLayerMaturity(modelPath, specModules);
95
+ const gateMat = 'ADVISORY';
96
+
97
+ // Extend registry entry
98
+ models[modelPath].source_layer = layer;
99
+ models[modelPath].gate_maturity = gateMat;
100
+ models[modelPath].layer_maturity = layerMaturity;
101
+
102
+ // Add to manifest layers
103
+ layers[layer].push({
104
+ path: modelPath,
105
+ description: models[modelPath].description || '',
106
+ grounding_status: layerMaturity > 0 ? 'has_semantic_declarations' : 'ungrounded'
107
+ });
108
+
109
+ maturityDist[layerMaturity] = (maturityDist[layerMaturity] || 0) + 1;
110
+ }
111
+
112
+ // Write updated model-registry.json
113
+ registry.last_sync = new Date().toISOString();
114
+ fs.writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2) + '\n', 'utf8');
115
+
116
+ // Generate layer-manifest.json
117
+ const manifest = {
118
+ schema_version: '1',
119
+ generated: new Date().toISOString(),
120
+ layers,
121
+ gate_relationships: {
122
+ A: { from: 'L1', to: 'L2', description: 'Evidence grounds semantic declarations' },
123
+ B: { from: 'L2', to: 'L3', description: 'Semantic declarations trace to reasoning models' },
124
+ C: { from: 'L3', to: 'TC', description: 'Reasoning models prove traceability completeness' }
125
+ },
126
+ summary: {
127
+ total_models: modelPaths.length,
128
+ L1_count: layers.L1.length,
129
+ L2_count: layers.L2.length,
130
+ L3_count: layers.L3.length,
131
+ maturity_distribution: maturityDist,
132
+ spec_modules_with_invariants: specModules.length
133
+ }
134
+ };
135
+
136
+ fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
137
+
138
+ // Output
139
+ if (JSON_FLAG) {
140
+ console.log(JSON.stringify(manifest, null, 2));
141
+ } else {
142
+ console.log(`Layer Manifest Generated`);
143
+ console.log(` Total models: ${modelPaths.length}`);
144
+ console.log(` L1 (Evidence): ${layers.L1.length}`);
145
+ console.log(` L2 (Semantics): ${layers.L2.length}`);
146
+ console.log(` L3 (Reasoning): ${layers.L3.length}`);
147
+ console.log(` Maturity 0 (ungrounded): ${maturityDist[0] || 0}`);
148
+ console.log(` Maturity 1 (has semantics): ${maturityDist[1] || 0}`);
149
+ console.log(` Spec modules with invariants: ${specModules.length}`);
150
+ }
151
+ }
152
+
153
+ main();
@@ -16,7 +16,7 @@
16
16
  * Reads providers.json, dispatches to the slot's CLI (subprocess) or HTTP provider,
17
17
  * prints the response text to stdout.
18
18
  *
19
- * Used by qgsd-quorum-orchestrator (sub-agent) which cannot access MCP tools.
19
+ * Used by nf-quorum-orchestrator (sub-agent) which cannot access MCP tools.
20
20
  *
21
21
  * Exit codes: 0 = success, 1 = error (message on stderr)
22
22
  */
@@ -205,8 +205,8 @@ if (!slot) {
205
205
  // ─── Find providers.json ───────────────────────────────────────────────────────
206
206
  function findProviders() {
207
207
  const searchPaths = [
208
- path.join(__dirname, 'providers.json'), // same dir (qgsd-bin)
209
- path.join(os.homedir(), '.claude', 'qgsd-bin', 'providers.json'), // installed fallback
208
+ path.join(__dirname, 'providers.json'), // same dir (nf-bin)
209
+ path.join(os.homedir(), '.claude', 'nf-bin', 'providers.json'), // installed fallback
210
210
  ];
211
211
 
212
212
  // Also derive path from unified-1 MCP server config in ~/.claude.json
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // bin/ccr-secure-config.cjs
3
- // Reads the 3 CCR provider API keys from keytar (qgsd service) and writes them
3
+ // Reads the 3 CCR provider API keys from keytar (nforma service) and writes them
4
4
  // into ~/.claude-code-router/config.json with chmod 600.
5
5
  // Designed to be called at session start and on-demand. Fail-silent when keytar
6
6
  // is unavailable or keys are not yet stored.
@@ -17,7 +17,7 @@ const CONFIG_PATH = path.join(os.homedir(), '.claude-code-router', 'config.json'
17
17
  // Locate secrets.cjs — try installed global path first, then local dev path.
18
18
  function findSecrets() {
19
19
  const candidates = [
20
- path.join(os.homedir(), '.claude', 'qgsd-bin', 'secrets.cjs'), // installed path
20
+ path.join(os.homedir(), '.claude', 'nf-bin', 'secrets.cjs'), // installed path
21
21
  path.join(__dirname, 'secrets.cjs'), // local dev path
22
22
  ];
23
23
  for (const p of candidates) {
@@ -39,9 +39,9 @@ async function main() {
39
39
 
40
40
  let akashKey, togetherKey, fireworksKey;
41
41
  try {
42
- akashKey = await secrets.get('qgsd', 'AKASHML_API_KEY');
43
- togetherKey = await secrets.get('qgsd', 'TOGETHER_API_KEY');
44
- fireworksKey = await secrets.get('qgsd', 'FIREWORKS_API_KEY');
42
+ akashKey = await secrets.get('nforma', 'AKASHML_API_KEY');
43
+ togetherKey = await secrets.get('nforma', 'TOGETHER_API_KEY');
44
+ fireworksKey = await secrets.get('nforma', 'FIREWORKS_API_KEY');
45
45
  } catch (e) {
46
46
  process.stderr.write('[ccr-secure-config] keytar unavailable: ' + e.message + '\n');
47
47
  process.exit(0);
@@ -5,7 +5,7 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
- // Forbidden SDK list — LLM SDKs that QGSD must not bundle (ARCH-10)
8
+ // Forbidden SDK list — LLM SDKs that nForma must not bundle (ARCH-10)
9
9
  // ---------------------------------------------------------------------------
10
10
 
11
11
  const FORBIDDEN_SDKS = [
@@ -12,7 +12,7 @@
12
12
  * Usage:
13
13
  * node bin/check-mcp-health.cjs [--timeout-ms N] [--json]
14
14
  *
15
- * Designed to be called at the start of /qgsd:quorum to skip
15
+ * Designed to be called at the start of /nf:quorum to skip
16
16
  * unresponsive servers before making full inference calls.
17
17
  */
18
18
 
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * No LLM inference is performed — this completes in ~2–3 seconds.
15
15
  *
16
- * TTL cache at ~/.claude/qgsd-provider-cache.json:
16
+ * TTL cache at ~/.claude/nf-provider-cache.json:
17
17
  * - DOWN entries: 5 minutes TTL
18
18
  * - UP entries: 3 minutes TTL
19
19
  * Cache is read before probing; stale or missing → probe runs normally.
@@ -54,7 +54,7 @@ const NO_CACHE = hasFlag('--no-cache');
54
54
  const CACHE_STATUS = hasFlag('--cache-status');
55
55
 
56
56
  // ─── TTL cache constants ──────────────────────────────────────────────────────
57
- const CACHE_FILE = path.join(os.homedir(), '.claude', 'qgsd-provider-cache.json');
57
+ const CACHE_FILE = path.join(os.homedir(), '.claude', 'nf-provider-cache.json');
58
58
  const TTL_DOWN_MS = 300000; // 5 minutes
59
59
  const TTL_UP_MS = 180000; // 3 minutes
60
60
 
@@ -122,11 +122,11 @@ try {
122
122
  process.exit(1);
123
123
  }
124
124
 
125
- // Load quorum_active from ~/.claude/qgsd.json (project config takes precedence)
125
+ // Load quorum_active from ~/.claude/nf.json (project config takes precedence)
126
126
  let quorumActive = [];
127
127
  try {
128
- const globalQgsd = path.join(os.homedir(), '.claude', 'qgsd.json');
129
- const projQgsd = path.join(process.cwd(), '.claude', 'qgsd.json');
128
+ const globalQgsd = path.join(os.homedir(), '.claude', 'nf.json');
129
+ const projQgsd = path.join(process.cwd(), '.claude', 'nf.json');
130
130
  for (const cfgPath of [globalQgsd, projQgsd]) {
131
131
  try {
132
132
  const cfgRaw = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
@@ -239,7 +239,7 @@ function probeUrl(baseUrl, apiKey) {
239
239
  const parsed = new URL(probeUrl);
240
240
  const lib = parsed.protocol === 'https:' ? https : http;
241
241
 
242
- const headers = { 'User-Agent': 'qgsd-health-check/1.0' };
242
+ const headers = { 'User-Agent': 'nf-health-check/1.0' };
243
243
  if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
244
244
 
245
245
  const req = lib.request(
@@ -3,22 +3,22 @@
3
3
  // bin/check-spec-sync.cjs
4
4
  // Verifies that formal specs stay in sync with the XState machine.
5
5
  //
6
- // The XState machine (src/machines/qgsd-workflow.machine.ts) is the SOURCE OF TRUTH.
6
+ // The XState machine (src/machines/nf-workflow.machine.ts) is the SOURCE OF TRUTH.
7
7
  // Formal specs must mirror it — not the other way around.
8
8
  //
9
9
  // Checks:
10
- // 1. State names in QGSDQuorum.tla TypeOK match the XState machine states
10
+ // 1. State names in NFQuorum.tla TypeOK match the XState machine states
11
11
  // 2. MaxDeliberation in MCsafety.cfg and MCliveness.cfg matches the XState context default
12
- // 3. Initial state in QGSDQuorum.tla Init matches the XState initial state
12
+ // 3. Initial state in NFQuorum.tla Init matches the XState initial state
13
13
  // 4. Alloy .als files do not reference state names or guard names not in XState machine
14
- // 5. Guard names in XState machine match keys in .planning/formal/tla/guards/qgsd-workflow.json (bidirectional)
14
+ // 5. Guard names in XState machine match keys in .planning/formal/tla/guards/nf-workflow.json (bidirectional)
15
15
  //
16
16
  // Exit 0 = in sync; Exit 1 = drift detected.
17
17
  // Usage: node bin/check-spec-sync.cjs [--tla-path=<path>] [--guards-path=<path>]
18
18
  //
19
19
  // CLI overrides (for fixture-based tests):
20
- // --tla-path=<abs-path> Override path to QGSDQuorum.tla (default: .planning/formal/tla/QGSDQuorum.tla)
21
- // --guards-path=<abs-path> Override path to guards JSON (default: .planning/formal/tla/guards/qgsd-workflow.json)
20
+ // --tla-path=<abs-path> Override path to NFQuorum.tla (default: .planning/formal/tla/NFQuorum.tla)
21
+ // --guards-path=<abs-path> Override path to guards JSON (default: .planning/formal/tla/guards/nf-workflow.json)
22
22
 
23
23
  const { buildSync } = require('esbuild');
24
24
  const fs = require('fs');
@@ -35,11 +35,11 @@ const guardsPathOverride = process.argv.find(a => a.startsWith('--guards-path=')
35
35
  // Resolved paths (absolute)
36
36
  const TLA_ABS_PATH = tlaPathOverride
37
37
  ? tlaPathOverride.slice('--tla-path='.length)
38
- : path.join(ROOT, '.planning', 'formal', 'tla', 'QGSDQuorum.tla');
38
+ : path.join(ROOT, '.planning', 'formal', 'tla', 'NFQuorum.tla');
39
39
 
40
40
  const GUARDS_ABS_PATH = guardsPathOverride
41
41
  ? guardsPathOverride.slice('--guards-path='.length)
42
- : path.join(ROOT, '.planning', 'formal', 'tla', 'guards', 'qgsd-workflow.json');
42
+ : path.join(ROOT, '.planning', 'formal', 'tla', 'guards', 'nf-workflow.json');
43
43
 
44
44
  // ── Load files ───────────────────────────────────────────────────────────────
45
45
  function load(rel) {
@@ -67,7 +67,7 @@ const livenessCfg = load('.planning/formal/tla/MCliveness.cfg');
67
67
  // Compile the TypeScript machine to a temporary CJS bundle, then require() it.
68
68
  // This gives us the live machine object — no regex parsing of raw source.
69
69
 
70
- const MACHINE_FILE = path.join(ROOT, 'src/machines/qgsd-workflow.machine.ts');
70
+ const MACHINE_FILE = path.join(ROOT, 'src/machines/nf-workflow.machine.ts');
71
71
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'check-spec-sync-'));
72
72
  const tmpBundle = path.join(tmpDir, 'machine.cjs');
73
73
 
@@ -128,7 +128,7 @@ if (machineObj && machineObj.config) {
128
128
  // Fallback: use regex if esbuild fails (e.g., in environments without esbuild)
129
129
  process.stderr.write('[check-spec-sync] esbuild extraction failed: ' + xstateExtractError + '\n');
130
130
  process.stderr.write('[check-spec-sync] Falling back to regex extraction (limited)\n');
131
- const machineSrc = load('src/machines/qgsd-workflow.machine.ts');
131
+ const machineSrc = load('src/machines/nf-workflow.machine.ts');
132
132
  xstateStateNames = (machineSrc.match(/^ ([A-Z_]+):\s*\{/gm) || []).map(l => l.trim().split(':')[0]);
133
133
  const md = machineSrc.match(/maxDeliberation:\s*(\d+)/);
134
134
  xstateMaxDelib = md ? parseInt(md[1], 10) : null;
@@ -161,7 +161,7 @@ function fail(msg) { errors.push(' FAIL ' + msg); }
161
161
  function warn(msg) { warnings.push(' WARN ' + msg); }
162
162
  function ok(msg) { process.stdout.write(' OK ' + msg + '\n'); }
163
163
 
164
- process.stdout.write('\n[check-spec-sync] Source of truth: src/machines/qgsd-workflow.machine.ts\n\n');
164
+ process.stdout.write('\n[check-spec-sync] Source of truth: src/machines/nf-workflow.machine.ts\n\n');
165
165
 
166
166
  // Check 1: State names
167
167
  if (xstateStateNames.length === 0) {
@@ -170,7 +170,7 @@ if (xstateStateNames.length === 0) {
170
170
  ok('XState states: ' + xstateStateNames.join(', '));
171
171
 
172
172
  if (tlaPhaseValues.length === 0) {
173
- fail('Could not parse phase values from QGSDQuorum.tla TypeOK');
173
+ fail('Could not parse phase values from NFQuorum.tla TypeOK');
174
174
  } else {
175
175
  ok('TLA+ phases: ' + tlaPhaseValues.join(', '));
176
176
 
@@ -182,7 +182,7 @@ if (xstateStateNames.length === 0) {
182
182
  }
183
183
  if (extra.length > 0) {
184
184
  fail('TLA+ TypeOK has orphaned phases not in XState machine: ' + extra.join(', ') +
185
- '\n (These TLA+ phases have no corresponding XState state — update QGSDQuorum.tla)');
185
+ '\n (These TLA+ phases have no corresponding XState state — update NFQuorum.tla)');
186
186
  }
187
187
  if (missing.length === 0 && extra.length === 0) {
188
188
  ok('State names match exactly');
@@ -226,7 +226,7 @@ if (xstateInitial === null) {
226
226
  ok('XState initial state: ' + xstateInitial);
227
227
 
228
228
  if (tlaInitPhase === null) {
229
- fail('Could not parse Init phase from QGSDQuorum.tla');
229
+ fail('Could not parse Init phase from NFQuorum.tla');
230
230
  } else if (tlaInitPhase !== xstateInitial) {
231
231
  fail(
232
232
  'TLA+ Init sets phase="' + tlaInitPhase +
@@ -244,7 +244,7 @@ if (xstateInitial === null) {
244
244
  //
245
245
  // Note: Alloy orphan detection uses warn() not fail() because Alloy models are intentional
246
246
  // abstractions — they may use different predicate names (e.g., MajorityReached instead of
247
- // minQuorumMet). The authoritative guard mapping check is in Check 5 (guards/qgsd-workflow.json).
247
+ // minQuorumMet). The authoritative guard mapping check is in Check 5 (guards/nf-workflow.json).
248
248
  const alloyDir = path.join(ROOT, '.planning', 'formal', 'alloy');
249
249
  if (fs.existsSync(alloyDir)) {
250
250
  const alsFiles = fs.readdirSync(alloyDir).filter(f => f.endsWith('.als'));
@@ -282,17 +282,17 @@ if (fs.existsSync(alloyDir)) {
282
282
  // Mapping context:
283
283
  // XState uses camelCase guard names (minQuorumMet, noInfiniteDeliberation, phaseMonotonicallyAdvances).
284
284
  // TLA+ uses PascalCase predicates (MinQuorumMet, DeliberationBounded) — different names, same semantics.
285
- // The bridge is .planning/formal/tla/guards/qgsd-workflow.json, which maps XState guard names to TLA+ expressions.
285
+ // The bridge is .planning/formal/tla/guards/nf-workflow.json, which maps XState guard names to TLA+ expressions.
286
286
  //
287
- // If a guard is renamed in the XState machine, it must also be updated in guards/qgsd-workflow.json.
288
- // If a mapping entry is removed from guards/qgsd-workflow.json without removing the guard from
287
+ // If a guard is renamed in the XState machine, it must also be updated in guards/nf-workflow.json.
288
+ // If a mapping entry is removed from guards/nf-workflow.json without removing the guard from
289
289
  // the machine (or vice versa), this check will detect the inconsistency.
290
290
  //
291
- // This check also corroborates by scanning QGSDQuorum.tla source text for camelCase guard name
291
+ // This check also corroborates by scanning NFQuorum.tla source text for camelCase guard name
292
292
  // occurrences (they appear in the header comment block as documentation of guard translations).
293
293
  if (xstateGuardNames.length > 0) {
294
294
  if (!fs.existsSync(GUARDS_ABS_PATH)) {
295
- fail('.planning/formal/tla/guards/qgsd-workflow.json not found — cannot verify guard name sync');
295
+ fail('.planning/formal/tla/guards/nf-workflow.json not found — cannot verify guard name sync');
296
296
  } else {
297
297
  let guardsJson = null;
298
298
  try {
@@ -306,28 +306,28 @@ if (xstateGuardNames.length > 0) {
306
306
  ok('Guards JSON mapped names: ' + mappedGuardNames.join(', '));
307
307
 
308
308
  // Forward check: XState guard → guards JSON (drift detection)
309
- // If a guard is renamed in XState but guards/qgsd-workflow.json still has the old name, this fires.
309
+ // If a guard is renamed in XState but guards/nf-workflow.json still has the old name, this fires.
310
310
  const missingFromMapping = xstateGuardNames.filter(g => !mappedGuardNames.includes(g));
311
311
  if (missingFromMapping.length > 0) {
312
312
  fail(
313
- 'XState guards not found in guards/qgsd-workflow.json: ' + missingFromMapping.join(', ') +
314
- '\n (Update .planning/formal/tla/guards/qgsd-workflow.json to map these guard names to their TLA+ predicates)'
313
+ 'XState guards not found in guards/nf-workflow.json: ' + missingFromMapping.join(', ') +
314
+ '\n (Update .planning/formal/tla/guards/nf-workflow.json to map these guard names to their TLA+ predicates)'
315
315
  );
316
316
  }
317
317
 
318
318
  // Reverse check: guards JSON → XState (orphan detection)
319
- // If a guard mapping entry exists in guards/qgsd-workflow.json but the guard was removed from
319
+ // If a guard mapping entry exists in guards/nf-workflow.json but the guard was removed from
320
320
  // the XState machine, this is an orphaned mapping.
321
321
  const orphanedGuards = mappedGuardNames.filter(g => !xstateGuardNames.includes(g));
322
322
  if (orphanedGuards.length > 0) {
323
323
  fail(
324
- 'guards/qgsd-workflow.json references guards not in XState machine: ' + orphanedGuards.join(', ') +
324
+ 'guards/nf-workflow.json references guards not in XState machine: ' + orphanedGuards.join(', ') +
325
325
  '\n (These guard mappings are orphaned — remove them or restore the XState guard)'
326
326
  );
327
327
  }
328
328
 
329
329
  if (missingFromMapping.length === 0 && orphanedGuards.length === 0) {
330
- ok('Guard names match exactly between XState machine and guards/qgsd-workflow.json');
330
+ ok('Guard names match exactly between XState machine and guards/nf-workflow.json');
331
331
  }
332
332
 
333
333
  // Corroboration: check TLA+ source mentions guard names in comment references
@@ -16,10 +16,10 @@ const VALIDATOR_FILE = 'bin/validate-traces.cjs';
16
16
 
17
17
  const KNOWN_EMITTERS = [
18
18
  'bin/validate-traces.cjs',
19
- 'hooks/qgsd-stop.js',
20
- 'hooks/qgsd-prompt.js',
21
- 'hooks/dist/qgsd-stop.js',
22
- 'hooks/dist/qgsd-prompt.js',
19
+ 'hooks/nf-stop.js',
20
+ 'hooks/nf-prompt.js',
21
+ 'hooks/dist/nf-stop.js',
22
+ 'hooks/dist/nf-prompt.js',
23
23
  ];
24
24
 
25
25
  /**
@@ -44,7 +44,7 @@ function checkSchemaDrift(changedFiles) {
44
44
  // but validator_updated alone does not satisfy emitter_updated — need a non-validator emitter
45
45
  // OR validate-traces.cjs satisfies both when it IS the emitter.
46
46
  // Per spec: atomic requires validator AND an emitter. validate-traces.cjs counts as emitter only
47
- // when a separate hook file (qgsd-stop.js, qgsd-prompt.js, etc.) is also present.
47
+ // when a separate hook file (nf-stop.js, nf-prompt.js, etc.) is also present.
48
48
  const NON_VALIDATOR_EMITTERS = KNOWN_EMITTERS.filter(e => e !== VALIDATOR_FILE);
49
49
  const emitterUpdated = changedFiles.some(f =>
50
50
  NON_VALIDATOR_EMITTERS.some(emitter => f === emitter || f.includes(emitter))
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
  // bin/conformance-schema.cjs
3
3
  // Single source of truth for conformance event field enumerations.
4
- // Imported by hooks (qgsd-stop.js, qgsd-prompt.js, qgsd-circuit-breaker.js) and validate-traces.cjs.
4
+ // Imported by hooks (nf-stop.js, nf-prompt.js, nf-circuit-breaker.js) and validate-traces.cjs.
5
5
  // NEVER add external require() calls — hooks have zero runtime dependencies.
6
6
 
7
- const VALID_ACTIONS = ['quorum_start', 'quorum_complete', 'quorum_block', 'deliberation_round', 'circuit_break'];
7
+ const VALID_ACTIONS = ['quorum_start', 'quorum_complete', 'quorum_block', 'deliberation_round', 'circuit_break', 'cache_hit', 'budget_warn', 'budget_downgrade', 'stall_detected', 'security_sweep'];
8
8
  const VALID_PHASES = ['IDLE', 'COLLECTING_VOTES', 'DELIBERATING', 'DECIDED'];
9
9
  const VALID_OUTCOMES = ['APPROVE', 'BLOCK', 'UNAVAILABLE', 'DELIBERATE'];
10
10
  const schema_version = '1';