forge-workflow 0.1.0-beta.6 → 0.1.0-beta.7

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 (156) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/docs/guides/MIGRATION.md +3 -3
  3. package/docs/reference/RELEASE.md +3 -3
  4. package/lib/commands/merge.js +2 -2
  5. package/lib/commands/push.js +13 -4
  6. package/lib/commands/shepherd.js +1 -1
  7. package/lib/commands/validate.js +13 -1
  8. package/lib/kernel/migrations.js +1 -1
  9. package/lib/kernel/sqlite-driver.js +1 -1
  10. package/lib/memory/router.js +1 -1
  11. package/lib/memory/usage-evidence.js +1 -1
  12. package/lib/pr-monitor/flow-monitor.js +2 -2
  13. package/lib/pr-monitor/reconcile-executor.js +1 -1
  14. package/lib/project-memory.js +1 -1
  15. package/lib/validation-receipt.js +190 -0
  16. package/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
  17. package/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
  18. package/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
  19. package/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
  20. package/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
  21. package/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
  22. package/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
  23. package/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
  24. package/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
  25. package/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
  26. package/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
  27. package/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
  28. package/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
  29. package/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
  30. package/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
  31. package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
  32. package/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
  33. package/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
  34. package/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
  35. package/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
  36. package/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
  37. package/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
  38. package/node_modules/@forge/contracts/index.js +32 -0
  39. package/node_modules/@forge/contracts/package.json +35 -0
  40. package/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
  41. package/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
  42. package/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
  43. package/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
  44. package/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
  45. package/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
  46. package/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
  47. package/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
  48. package/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
  49. package/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
  50. package/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
  51. package/node_modules/@forge/contracts/src/baseline.js +23 -0
  52. package/node_modules/@forge/contracts/src/canonical.js +151 -0
  53. package/node_modules/@forge/contracts/src/definitions.js +176 -0
  54. package/node_modules/@forge/contracts/src/identity.js +42 -0
  55. package/node_modules/@forge/contracts/src/schema.js +72 -0
  56. package/node_modules/@forge/contracts/src/validate.js +305 -0
  57. package/node_modules/@forge/flow/index.js +114 -0
  58. package/node_modules/@forge/flow/package.json +34 -0
  59. package/node_modules/@forge/flow/src/bounded-loop.js +415 -0
  60. package/node_modules/@forge/flow/src/efficiency-supervisor.js +89 -0
  61. package/node_modules/@forge/flow/src/executor.js +279 -0
  62. package/node_modules/@forge/flow/src/monitor-durability.js +419 -0
  63. package/node_modules/@forge/flow/src/monitor-runtime.js +460 -0
  64. package/node_modules/@forge/flow/src/process-lifecycle.js +469 -0
  65. package/node_modules/@forge/flow/src/skill-runtime.js +343 -0
  66. package/node_modules/@forge/memory/index.js +331 -0
  67. package/node_modules/@forge/memory/package.json +34 -0
  68. package/node_modules/@forge/memory/src/authority-provider.js +67 -0
  69. package/node_modules/@forge/memory/src/backend-registry.js +166 -0
  70. package/node_modules/@forge/memory/src/feedback-intake.js +243 -0
  71. package/node_modules/@forge/memory/src/pr-lifecycle-authority.js +946 -0
  72. package/node_modules/@forge/memory/src/usage-evidence.js +205 -0
  73. package/package.json +9 -1
  74. package/packages/flow/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
  75. package/packages/flow/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
  76. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
  77. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
  78. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
  79. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
  80. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
  81. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
  82. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
  83. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
  84. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
  85. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
  86. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
  87. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
  88. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
  89. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
  90. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
  91. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
  92. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
  93. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
  94. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
  95. package/packages/flow/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
  96. package/packages/flow/node_modules/@forge/contracts/index.js +32 -0
  97. package/packages/flow/node_modules/@forge/contracts/package.json +35 -0
  98. package/packages/flow/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
  99. package/packages/flow/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
  100. package/packages/flow/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
  101. package/packages/flow/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
  102. package/packages/flow/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
  103. package/packages/flow/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
  104. package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
  105. package/packages/flow/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
  106. package/packages/flow/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
  107. package/packages/flow/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
  108. package/packages/flow/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
  109. package/packages/flow/node_modules/@forge/contracts/src/baseline.js +23 -0
  110. package/packages/flow/node_modules/@forge/contracts/src/canonical.js +151 -0
  111. package/packages/flow/node_modules/@forge/contracts/src/definitions.js +176 -0
  112. package/packages/flow/node_modules/@forge/contracts/src/identity.js +42 -0
  113. package/packages/flow/node_modules/@forge/contracts/src/schema.js +72 -0
  114. package/packages/flow/node_modules/@forge/contracts/src/validate.js +305 -0
  115. package/packages/memory/node_modules/@forge/contracts/compatibility-matrix.v1.json +1 -0
  116. package/packages/memory/node_modules/@forge/contracts/contract-baseline.v1.json +134 -0
  117. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/canonical-hash.json +1 -0
  118. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/contract-inputs.v1.json +71 -0
  119. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/feedback-secret-reject.json +1 -0
  120. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/identity-conflict.json +1 -0
  121. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-envelope-inputs.v1.json +16 -0
  122. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/malformed-missing-required.json +1 -0
  123. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-bounds-reject.json +1 -0
  124. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/monitor-receipt-privacy-reject.json +1 -0
  125. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/not-executed-receipt.json +1 -0
  126. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/privacy-redaction.json +1 -0
  127. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/retry-identical.json +1 -0
  128. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/stale-authority-reject.json +1 -0
  129. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-privacy-reject.json +1 -0
  130. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-live-reject.json +1 -0
  131. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/structured-error-stripe-test-reject.json +1 -0
  132. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-advisory-roundtrip.json +1 -0
  133. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/unknown-consequential-reject.json +1 -0
  134. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-full.json +1 -0
  135. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/valid-minimal.json +1 -0
  136. package/packages/memory/node_modules/@forge/contracts/fixtures/v1/wrong-capability-digest.json +1 -0
  137. package/packages/memory/node_modules/@forge/contracts/index.js +32 -0
  138. package/packages/memory/node_modules/@forge/contracts/package.json +35 -0
  139. package/packages/memory/node_modules/@forge/contracts/schemas/v1/capability-manifest.schema.json +1 -0
  140. package/packages/memory/node_modules/@forge/contracts/schemas/v1/claim-request.schema.json +1 -0
  141. package/packages/memory/node_modules/@forge/contracts/schemas/v1/context-packet.schema.json +1 -0
  142. package/packages/memory/node_modules/@forge/contracts/schemas/v1/delivery-receipt.schema.json +1 -0
  143. package/packages/memory/node_modules/@forge/contracts/schemas/v1/feedback-report.schema.json +1 -0
  144. package/packages/memory/node_modules/@forge/contracts/schemas/v1/lease-receipt.schema.json +1 -0
  145. package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-event.schema.json +1 -0
  146. package/packages/memory/node_modules/@forge/contracts/schemas/v1/monitor-receipt.schema.json +1 -0
  147. package/packages/memory/node_modules/@forge/contracts/schemas/v1/run-receipt.schema.json +1 -0
  148. package/packages/memory/node_modules/@forge/contracts/schemas/v1/structured-error.schema.json +1 -0
  149. package/packages/memory/node_modules/@forge/contracts/schemas/v1/work-packet.schema.json +1 -0
  150. package/packages/memory/node_modules/@forge/contracts/src/baseline.js +23 -0
  151. package/packages/memory/node_modules/@forge/contracts/src/canonical.js +151 -0
  152. package/packages/memory/node_modules/@forge/contracts/src/definitions.js +176 -0
  153. package/packages/memory/node_modules/@forge/contracts/src/identity.js +42 -0
  154. package/packages/memory/node_modules/@forge/contracts/src/schema.js +72 -0
  155. package/packages/memory/node_modules/@forge/contracts/src/validate.js +305 -0
  156. package/scripts/test.js +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  > **Note**: `/check` was renamed to `/validate` and `/merge` was renamed to `/premerge` in v0.0.3. Historical entries below may use the old names.
9
9
 
10
+ ## [0.1.0-beta.7] - 2026-09-11
11
+
12
+ ### Changed
13
+
14
+ - **A clean full validation is reused by the next unchanged `forge push`.** Forge stores a one-hour, signed local receipt bound to the canonical worktree, exact HEAD, clean state, Forge, Bun, and Node runtimes, and complete nonzero gate results. Branch protection and lint still run; invalid or stale evidence falls back to the full suite, while raw Git pushes and CI remain independent.
15
+ - **A local full suite no longer reruns its already-included E2E directory.** Targeted E2E execution is unchanged, while full validation avoids an exact duplicate. (issue `4aed2cc8-57eb-451b-bb3a-02bbdd93af49`)
16
+ - **The shared public contract package is now `@forge/contracts`.** The product-neutral name replaces the former unpublished Memory-qualified name before beta.7, and all three scoped packages explicitly publish as public MIT packages linked to the public Forge repository. (issue `4d41ffb7-8793-4a17-a30b-92130db69672`)
17
+
18
+ ### Fixed
19
+
20
+ - **The npm package now includes every internal runtime workspace.** Root runtime imports use the `@forge/memory`, `@forge/contracts`, and `@forge/flow` package boundaries, and npm bundles those unpublished workspaces into `forge-workflow`. The installed-package smoke accepts npm 10 lifecycle output before its JSON payload, so Node 22 verifies the same package correctly. A fresh packed install now runs `forge --version` and `forge setup --quick --yes`, preventing the `MODULE_NOT_FOUND` failure in v0.1.0-beta.6. (issue `95372af8-da00-42e0-af64-0111ddab3405`)
21
+
10
22
  ## [0.1.0-beta.6] - 2026-09-11
11
23
 
12
24
  ### Added
@@ -1,6 +1,6 @@
1
1
  # Migration Guide
2
2
 
3
- Use this guide when moving older Forge docs, habits, or installed scaffolding toward the v0.1.0-beta.6 public framing.
3
+ Use this guide when moving older Forge docs, habits, or installed scaffolding toward the v0.1.0-beta.7 public framing.
4
4
 
5
5
  ## What Changed
6
6
 
@@ -39,8 +39,8 @@ forge setup --agents claude,cursor
39
39
 
40
40
  ## Version Labels
41
41
 
42
- - `0.1.0-beta.6` is the current prerelease package version.
43
- - `0.1.0-beta.5` is the previous prerelease package version.
42
+ - `0.1.0-beta.7` is the current prerelease package version.
43
+ - `0.1.0-beta.6` is the previous prerelease package version, but its npm tarball omits required runtime workspaces; upgrade directly to beta.7.
44
44
  - Internal labels such as `0.0.19` or `v3` describe roadmap slices or historical codenames. Do not present them as current package versions.
45
45
 
46
46
  ## Safe Upgrade Path
@@ -2,9 +2,9 @@
2
2
 
3
3
  This page documents release readiness. Package publishing still requires the explicit publish step after merge.
4
4
 
5
- ## v0.1.0-beta.6 Boundary
5
+ ## v0.1.0-beta.7 Boundary
6
6
 
7
- v0.1.0-beta.6 is the current prerelease boundary. The release branch declares `0.1.0-beta.6`; publish only after the release PR is merged, tagged, and validated on that exact SHA.
7
+ v0.1.0-beta.7 is the current prerelease boundary. The release branch declares `0.1.0-beta.7`; publish only after the release PR is merged, tagged, and validated on that exact SHA.
8
8
 
9
9
  Keep these release steps explicit:
10
10
 
@@ -43,7 +43,7 @@ Release notes should include:
43
43
  - adapter compatibility
44
44
  - DeepWiki refresh checklist
45
45
 
46
- The v0.1.0-beta.6 release notes live in [CHANGELOG.md](../../CHANGELOG.md).
46
+ The v0.1.0-beta.7 release notes live in [CHANGELOG.md](../../CHANGELOG.md).
47
47
 
48
48
  ## Rollback
49
49
 
@@ -47,7 +47,7 @@ const { runIssueOperation } = require('../forge-issues');
47
47
  const { PrStateAdapter } = require('../adapters/pr-state-adapter');
48
48
  const { stripGlobalFlags } = require('../global-flags');
49
49
  const gateCommand = require('./gate');
50
- const { computeContentHash, validateContractStructure } = require('../../packages/memory-contracts');
50
+ const { computeContentHash, validateContractStructure } = require('@forge/contracts');
51
51
 
52
52
  const FULL_HEAD_SHA = /^[0-9a-f]{40}$/i;
53
53
  const FORGE_ISSUE_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -560,7 +560,7 @@ async function defaultRecordMergeDecision({ decision, mergeResult, pr, expectedH
560
560
  built = { broker: deps.kernelBroker, driver: deps.kernelDriver };
561
561
  }
562
562
  if (!built?.broker) throw new Error('Kernel lifecycle provider is unavailable.');
563
- const { createMemoryAuthorityProvider } = require('../../packages/memory');
563
+ const { createMemoryAuthorityProvider } = require('@forge/memory');
564
564
  const provider = createMemoryAuthorityProvider({ broker: built.broker });
565
565
  await provider.recordPrLinkage({
566
566
  phase: 'merged',
@@ -6,6 +6,7 @@ const path = require('node:path');
6
6
  const forgeToken = require('../../scripts/check-forge-token');
7
7
  const { QUICK_LANE_ENV_VAR, QUICK_LANE_VALUE, resolveFullSuiteTimeoutMs } = require('../../scripts/test');
8
8
  const { fireAndForget } = require('../pr-monitor/reconcile-executor');
9
+ const { verifyValidationReceipt } = require('../validation-receipt');
9
10
 
10
11
  const isWindows = process.platform === 'win32';
11
12
 
@@ -346,6 +347,7 @@ module.exports = {
346
347
  const existsFn = deps?.existsSync || fs.existsSync;
347
348
  const log = deps?.log || console.log;
348
349
  const tokenWrite = deps?.writeForgeToken || forgeToken.write;
350
+ const verifyReceipt = deps?.verifyValidationReceipt || verifyValidationReceipt;
349
351
 
350
352
  const quickMode = !!(flags && (flags['--quick'] || flags.quick));
351
353
  const pkgManager = detectPackageManager(projectRoot, existsFn);
@@ -368,9 +370,16 @@ module.exports = {
368
370
  }
369
371
 
370
372
  // Step 3: Tests (skip in quick mode)
371
- const testsPassed = runTests(spawnFn, execFn, pkgManager, projectRoot, quickMode, log, deps?.env || process.env);
373
+ const receipt = quickMode
374
+ ? { valid: false }
375
+ : verifyReceipt(resolveGitToplevel(execFn, projectRoot));
376
+ const validationReused = receipt.valid === true;
377
+ if (validationReused) log(`Tests reused from full validation at ${receipt.head || 'current HEAD'}`);
378
+ const testsPassed = validationReused
379
+ ? true
380
+ : runTests(spawnFn, execFn, pkgManager, projectRoot, quickMode, log, deps?.env || process.env);
372
381
  if (!quickMode && !testsPassed) {
373
- return { success: false, quickMode, lintPassed: true, testsPassed: false, pushed: false };
382
+ return { success: false, quickMode, lintPassed: true, testsPassed: false, validationReused, pushed: false };
374
383
  }
375
384
 
376
385
  // Step 4: Write nonce token so lefthook skips pre-push hooks.
@@ -392,7 +401,7 @@ module.exports = {
392
401
  success: false,
393
402
  quickMode,
394
403
  lintPassed: true,
395
- ...(quickMode ? {} : { testsPassed: true }),
404
+ ...(quickMode ? {} : { testsPassed: true, validationReused }),
396
405
  pushed: false,
397
406
  };
398
407
  }
@@ -407,7 +416,7 @@ module.exports = {
407
416
  success: true,
408
417
  quickMode,
409
418
  lintPassed: true,
410
- ...(quickMode ? {} : { testsPassed: true }),
419
+ ...(quickMode ? {} : { testsPassed: true, validationReused }),
411
420
  pushed: true,
412
421
  };
413
422
  },
@@ -313,7 +313,7 @@ async function buildMonitorContext(pr, projectRoot, deps) {
313
313
  const buildKernelDeps = deps.buildKernelDeps
314
314
  || require('../kernel/cli-broker-factory').buildMigratedKernelIssueDeps;
315
315
  const createMonitorStore = deps.createMonitorStore
316
- || require('../../packages/memory').createMonitorStore;
316
+ || require('@forge/memory').createMonitorStore;
317
317
  let kernel;
318
318
  try {
319
319
  kernel = await buildKernelDeps({ projectRoot: projectRoot || process.cwd(), gitCommonDir });
@@ -12,6 +12,7 @@ const { execFileSync } = require('node:child_process');
12
12
  const fs = require('node:fs');
13
13
  const path = require('node:path');
14
14
  const { secureExecFileSync } = require('../shell-utils');
15
+ const validationReceipt = require('../validation-receipt');
15
16
 
16
17
  // Constants
17
18
  const CHECK_TYPES = {
@@ -299,6 +300,7 @@ async function runTypeCheck() {
299
300
  return {
300
301
  success: true,
301
302
  skipped: true,
303
+ notConfigured: true,
302
304
  duration: Date.now() - startTime,
303
305
  message: 'TypeScript not configured (no tsconfig.json)',
304
306
  };
@@ -632,6 +634,7 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
632
634
  success: true,
633
635
  skipped: true,
634
636
  testsFound: false,
637
+ fullSuite: useFullSuite,
635
638
  duration: Date.now() - startTime,
636
639
  passed,
637
640
  failed,
@@ -643,6 +646,7 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
643
646
  return {
644
647
  success,
645
648
  testsFound: true,
649
+ fullSuite: useFullSuite,
646
650
  duration: Date.now() - startTime,
647
651
  passed,
648
652
  failed,
@@ -657,6 +661,7 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
657
661
  if (error.code === 'ETIMEDOUT' || (error.killed && error.signal === 'SIGTERM')) {
658
662
  return {
659
663
  success: false,
664
+ fullSuite: useFullSuite,
660
665
  duration: Date.now() - startTime,
661
666
  passed: 0,
662
667
  failed: 0,
@@ -671,6 +676,7 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
671
676
  success: true,
672
677
  skipped: true,
673
678
  testsFound: false,
679
+ fullSuite: useFullSuite,
674
680
  duration: Date.now() - startTime,
675
681
  passed: 0,
676
682
  failed: 0,
@@ -691,6 +697,7 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
691
697
  return {
692
698
  success: false,
693
699
  testsFound: counts.testsFound,
700
+ fullSuite: useFullSuite,
694
701
  duration: Date.now() - startTime,
695
702
  passed,
696
703
  failed,
@@ -724,6 +731,9 @@ async function runAllTests(exec = execFileSync, rootDir = process.cwd()) {
724
731
  */
725
732
  async function executeValidate(options = {}) { // NOSONAR S3776
726
733
  const { skip = [], continueOnError = true, rootDir = process.cwd() } = options || {};
734
+ const receiptApi = options?.validationReceipt || validationReceipt;
735
+ const validationSnapshot = receiptApi.beginValidation(rootDir);
736
+ const receiptSnapshot = skip.length === 0 ? validationSnapshot : null;
727
737
 
728
738
  const checks = {};
729
739
  const failedChecks = [];
@@ -810,7 +820,9 @@ async function executeValidate(options = {}) { // NOSONAR S3776
810
820
  }
811
821
  }
812
822
 
813
- return buildResult(checks, failedChecks, errors, startTime);
823
+ const result = buildResult(checks, failedChecks, errors, startTime);
824
+ result.validationReceipt = receiptApi.completeValidation(rootDir, receiptSnapshot, result);
825
+ return result;
814
826
  }
815
827
 
816
828
  /**
@@ -1,5 +1,5 @@
1
1
  const { getKernelSchema, validateKernelSchema } = require('./schema');
2
- const { USAGE_EVIDENCE_MIGRATION } = require('../../packages/memory');
2
+ const { USAGE_EVIDENCE_MIGRATION } = require('@forge/memory');
3
3
 
4
4
  function assertIdentifier(identifier, label) {
5
5
  if (!/^[a-z][a-z0-9_]*$/.test(identifier)) {
@@ -30,7 +30,7 @@ const {
30
30
  const { CONFLICT_SIGNAL, classifyConflictSignal } = require('./conflict-signal');
31
31
  const { normalizeRecallHit } = require('../memory-recall');
32
32
  const { getPackageRoot } = require('../package-root');
33
- const { appendUsageEvidence, rebuildUsageProjection } = require('../../packages/memory');
33
+ const { appendUsageEvidence, rebuildUsageProjection } = require('@forge/memory');
34
34
 
35
35
  const BUILTIN_SQLITE_RUNTIME_ORDER = Object.freeze(['bun:sqlite', 'node:sqlite']);
36
36
  let probeCounter = 0;
@@ -32,7 +32,7 @@ const projectMemory = require('../project-memory');
32
32
  const {
33
33
  assertBackend,
34
34
  createMemoryBackendRegistry,
35
- } = require('../../packages/memory');
35
+ } = require('@forge/memory');
36
36
 
37
37
  /** Supported PUBLIC backends, default first. */
38
38
  const MEMORY_BACKENDS = ['local', 'graphiti'];
@@ -1,4 +1,4 @@
1
1
  'use strict';
2
2
 
3
3
  // Compatibility shim: the durable usage contract belongs to @forge/memory.
4
- module.exports = require('../../packages/memory');
4
+ module.exports = require('@forge/memory');
@@ -3,7 +3,7 @@
3
3
  const crypto = require('node:crypto');
4
4
  const zlib = require('node:zlib');
5
5
 
6
- const { computeContentHash, validateContractStructure } = require('../../packages/memory-contracts');
6
+ const { computeContentHash, validateContractStructure } = require('@forge/contracts');
7
7
  const {
8
8
  MonitorRuntimeError,
9
9
  createMonitorDurabilityBridge,
@@ -11,7 +11,7 @@ const {
11
11
  createMonitorState,
12
12
  reduceMonitor,
13
13
  reduceMonitorBatch,
14
- } = require('../../packages/flow');
14
+ } = require('@forge/flow');
15
15
  const { diffSnapshots } = require('./differ');
16
16
  const { EVENT_TYPES: T, makeEvent } = require('./events');
17
17
  const { finalizeRecords, MAX_EVENT_DELTAS } = require('./monitor');
@@ -1081,7 +1081,7 @@ async function migrateLegacyAuthority(projectRoot, opts = {}) {
1081
1081
 
1082
1082
  async function defaultBuildBroker({ projectRoot, gitCommonDir }) {
1083
1083
  const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
1084
- const { createMonitorStore } = require('../../packages/memory');
1084
+ const { createMonitorStore } = require('@forge/memory');
1085
1085
  const deps = await buildMigratedKernelIssueDeps({ projectRoot, gitCommonDir });
1086
1086
  const store = createMonitorStore(deps.kernelDriver);
1087
1087
  return {
@@ -8,7 +8,7 @@ const { resolveKernelDatabasePath } = require('./kernel/cli-broker-factory');
8
8
  const { resolveGitCommonDir } = require('./kernel/broker');
9
9
  const { createBuiltinSQLiteDriver } = require('./kernel/sqlite-driver');
10
10
  const { normalizeRecallHit } = require('./memory-recall');
11
- const { createUsageEvidenceStore } = require('../packages/memory');
11
+ const { createUsageEvidenceStore } = require('@forge/memory');
12
12
 
13
13
  // Project memory is a Forge read model persisted in the kernel store (kernel_memories),
14
14
  // written DIRECTLY rather than through the issue CAS/guarded-event path. The store seam
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const { execFileSync } = require('node:child_process');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+ const { resolveWorktreeScope } = require('./protected-state-authority');
9
+
10
+ const SCHEMA_VERSION = 1;
11
+ const RECEIPT_TTL_MS = 60 * 60 * 1000;
12
+ const FUTURE_SKEW_MS = 60 * 1000;
13
+ const RUNNER_ID = 'forge-full-suite-v1';
14
+
15
+ function git(projectRoot, args, deps = {}) {
16
+ return (deps.execFileSync || execFileSync)('git', args, {
17
+ cwd: projectRoot,
18
+ encoding: 'utf8',
19
+ stdio: ['ignore', 'pipe', 'pipe'],
20
+ }).trim();
21
+ }
22
+
23
+ function resolveGitRoot(projectRoot, deps = {}) {
24
+ return path.resolve(git(projectRoot, ['rev-parse', '--show-toplevel'], deps));
25
+ }
26
+
27
+ function resolveReceiptPath(projectRoot, deps = {}) {
28
+ const root = resolveGitRoot(projectRoot, deps);
29
+ const gitPath = git(root, ['rev-parse', '--git-path', 'forge/validation-receipt.json'], deps);
30
+ return path.resolve(root, gitPath);
31
+ }
32
+
33
+ function resolveKeyPath(deps = {}) {
34
+ return path.join(deps.homeDir || os.homedir(), '.forge', 'validation-receipt.key');
35
+ }
36
+
37
+ function runtimeIdentity(deps = {}) {
38
+ return deps.runtimeIdentity
39
+ || [process.platform, process.arch, process.versions.node, process.versions.bun || 'node'].join(':');
40
+ }
41
+
42
+ function commandIdentity(command, projectRoot, env, run) {
43
+ const version = run(command, ['--version'], {
44
+ cwd: projectRoot,
45
+ encoding: 'utf8',
46
+ env,
47
+ stdio: ['ignore', 'pipe', 'pipe'],
48
+ }).trim();
49
+ const located = path.isAbsolute(command)
50
+ ? fs.realpathSync.native(command)
51
+ : run(process.platform === 'win32' ? 'where.exe' : 'which', [command], {
52
+ encoding: 'utf8',
53
+ env,
54
+ stdio: ['ignore', 'pipe', 'pipe'],
55
+ }).trim().split(/\r?\n/)[0];
56
+ return `${process.platform === 'win32' ? located.toLowerCase() : located}:${version}`;
57
+ }
58
+
59
+ function testRuntimeIdentity(projectRoot, deps = {}) {
60
+ if (deps.testRuntimeIdentity) return deps.testRuntimeIdentity;
61
+ const env = deps.env || process.env;
62
+ const run = deps.runtimeExecFileSync || execFileSync;
63
+ return [env.BUN_EXE || 'bun', 'node']
64
+ .map(command => commandIdentity(command, projectRoot, env, run))
65
+ .join('|');
66
+ }
67
+
68
+ function captureState(projectRoot, deps = {}) {
69
+ const root = resolveGitRoot(projectRoot, deps);
70
+ return {
71
+ worktree: resolveWorktreeScope(root, deps),
72
+ head: git(root, ['rev-parse', 'HEAD'], deps),
73
+ clean: git(root, ['status', '--porcelain=v1', '--untracked-files=all'], deps) === '',
74
+ runtime: runtimeIdentity(deps),
75
+ testRuntime: testRuntimeIdentity(root, deps),
76
+ runner: RUNNER_ID,
77
+ };
78
+ }
79
+
80
+ function sameState(left, right) {
81
+ return left?.clean === true
82
+ && right?.clean === true
83
+ && left.worktree === right.worktree
84
+ && left.head === right.head
85
+ && left.runtime === right.runtime
86
+ && left.testRuntime === right.testRuntime
87
+ && left.runner === right.runner;
88
+ }
89
+
90
+ function validationIsComplete(result) {
91
+ const checks = result?.checks || {};
92
+ const tests = checks.tests || {};
93
+ return result?.success === true
94
+ && checks.conflictMarkers?.success === true
95
+ && checks.typeCheck?.success === true
96
+ && (checks.typeCheck.skipped !== true || checks.typeCheck.notConfigured === true)
97
+ && checks.lint?.success === true && checks.lint?.skipped !== true
98
+ && checks.security?.success === true && checks.security?.skipped !== true
99
+ && tests.success === true && tests.skipped !== true
100
+ && tests.fullSuite === true && tests.testsFound === true
101
+ && tests.total > 0 && tests.failed === 0;
102
+ }
103
+
104
+ function readOrCreateKey(deps = {}) {
105
+ const keyPath = resolveKeyPath(deps);
106
+ fs.mkdirSync(path.dirname(keyPath), { recursive: true });
107
+ try {
108
+ fs.writeFileSync(keyPath, crypto.randomBytes(32), { flag: 'wx', mode: 0o600 });
109
+ } catch (error) {
110
+ if (error.code !== 'EEXIST') throw error;
111
+ }
112
+ return fs.readFileSync(keyPath);
113
+ }
114
+
115
+ function sign(payload, deps = {}) {
116
+ return crypto.createHmac('sha256', readOrCreateKey(deps))
117
+ .update(JSON.stringify(payload))
118
+ .digest('hex');
119
+ }
120
+
121
+ function signatureMatches(payload, signature, deps = {}) {
122
+ if (!/^[a-f0-9]{64}$/.test(signature || '')) return false;
123
+ const expected = Buffer.from(sign(payload, deps), 'hex');
124
+ const actual = Buffer.from(signature, 'hex');
125
+ return actual.length === expected.length && crypto.timingSafeEqual(actual, expected);
126
+ }
127
+
128
+ function writeAtomic(filePath, content) {
129
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
130
+ const temporary = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
131
+ try {
132
+ fs.writeFileSync(temporary, content, { flag: 'wx', mode: 0o600 });
133
+ fs.renameSync(temporary, filePath);
134
+ } finally {
135
+ fs.rmSync(temporary, { force: true });
136
+ }
137
+ }
138
+
139
+ function beginValidation(projectRoot, deps = {}) {
140
+ try {
141
+ fs.rmSync(resolveReceiptPath(projectRoot, deps), { force: true });
142
+ const state = captureState(projectRoot, deps);
143
+ return state.clean ? state : null;
144
+ } catch {
145
+ return null;
146
+ }
147
+ }
148
+
149
+ function completeValidation(projectRoot, snapshot, result, deps = {}) {
150
+ try {
151
+ if (!snapshot || !validationIsComplete(result)) return false;
152
+ const current = captureState(projectRoot, deps);
153
+ if (!sameState(snapshot, current)) return false;
154
+ const issuedAt = (deps.now || Date.now)();
155
+ const payload = {
156
+ schemaVersion: SCHEMA_VERSION,
157
+ ...current,
158
+ issuedAt,
159
+ expiresAt: issuedAt + RECEIPT_TTL_MS,
160
+ gates: ['conflictMarkers', 'typeCheck', 'lint', 'security', 'tests'],
161
+ };
162
+ writeAtomic(resolveReceiptPath(projectRoot, deps), JSON.stringify({ payload, signature: sign(payload, deps) }));
163
+ return true;
164
+ } catch {
165
+ return false;
166
+ }
167
+ }
168
+
169
+ function verifyValidationReceipt(projectRoot, deps = {}) {
170
+ try {
171
+ const receipt = JSON.parse(fs.readFileSync(resolveReceiptPath(projectRoot, deps), 'utf8'));
172
+ if (receipt?.payload?.schemaVersion !== SCHEMA_VERSION) return { valid: false, reason: 'schema' };
173
+ if (!signatureMatches(receipt.payload, receipt.signature, deps)) return { valid: false, reason: 'signature' };
174
+ const now = (deps.now || Date.now)();
175
+ if (receipt.payload.issuedAt > now + FUTURE_SKEW_MS) return { valid: false, reason: 'future' };
176
+ if (receipt.payload.expiresAt < now) return { valid: false, reason: 'expired' };
177
+ if (!sameState(receipt.payload, captureState(projectRoot, deps))) return { valid: false, reason: 'state' };
178
+ return { valid: true, head: receipt.payload.head };
179
+ } catch {
180
+ return { valid: false, reason: 'missing-or-invalid' };
181
+ }
182
+ }
183
+
184
+ module.exports = {
185
+ beginValidation,
186
+ completeValidation,
187
+ resolveReceiptPath,
188
+ validationIsComplete,
189
+ verifyValidationReceipt,
190
+ };
@@ -0,0 +1 @@
1
+ {"matrix_version":1,"readers":{"0.1.0-beta.6":{"accepted":{"forge.memory.work-packet.v1":[1],"forge.memory.context-packet.v1":[1],"forge.memory.claim-request.v1":[1],"forge.memory.lease-receipt.v1":[1],"forge.memory.capability-manifest.v1":[1],"forge.memory.run-receipt.v1":[1],"forge.memory.feedback-report.v1":[1],"forge.memory.structured-error.v1":[1],"forge.memory.monitor-event.v1":[1],"forge.memory.delivery-receipt.v1":[1],"forge.memory.monitor-receipt.v1":[1]},"validation_surfaces":{"structural":"no_authority_or_freshness_claim","consequential":"requires_independent_live_expected"},"schema_annotations":{"generic_json_schema_enforces_x_forge":false,"conformance_helper":"validateContractStructure","requirement":"x-forge bounds and privacy annotations require the Forge runtime validator"},"run_receipt_non_authoritative_statuses":["NOT_EXECUTED"],"unknown_advisory":"preserve","unknown_consequential":"reject","unknown_schema_version":"reject"}}}
@@ -0,0 +1,134 @@
1
+ {
2
+ "baseline_version": 1,
3
+ "generator_version": "contracts-schema-gen/7",
4
+ "artifacts": [
5
+ {
6
+ "path": "compatibility-matrix.v1.json",
7
+ "sha256": "4ca93d10ae9bff80dd3785bb5ebfc77610cf19e928b9b9ae3f6a1ad9c2fea18e"
8
+ },
9
+ {
10
+ "path": "fixtures/v1/canonical-hash.json",
11
+ "sha256": "469c5b83ebe5e02601cd41b83f35f013f8fb4b118b8e213dc1790bb61301dc3c"
12
+ },
13
+ {
14
+ "path": "fixtures/v1/contract-inputs.v1.json",
15
+ "sha256": "40f28821f77ea153259a43e0ca8a5d6611f3e5e0ec4e4e47114d4cddeadac3fc"
16
+ },
17
+ {
18
+ "path": "fixtures/v1/feedback-secret-reject.json",
19
+ "sha256": "d2a8762a169617a6c98f5654e1d5265732485037e55af107018d139895b47869"
20
+ },
21
+ {
22
+ "path": "fixtures/v1/identity-conflict.json",
23
+ "sha256": "c703733d89f8adb079fb0e0ffe01ad35238d9a5f3ae725af54bca8b518fd6039"
24
+ },
25
+ {
26
+ "path": "fixtures/v1/malformed-envelope-inputs.v1.json",
27
+ "sha256": "17354a1178523332645f27d506eeabaa39eb6ea6bfa448807f7d0b8d4a1226f2"
28
+ },
29
+ {
30
+ "path": "fixtures/v1/malformed-missing-required.json",
31
+ "sha256": "e4031505309e8b172d274ef7c4ef617e71217742ff2b7285f37859db0eea42b9"
32
+ },
33
+ {
34
+ "path": "fixtures/v1/monitor-bounds-reject.json",
35
+ "sha256": "36594e37f3707572ec73c60134f24f5fb3ae17a41d804c409fc03a83e9716c26"
36
+ },
37
+ {
38
+ "path": "fixtures/v1/monitor-receipt-privacy-reject.json",
39
+ "sha256": "e2c53bc43d727d3583f9f2da6538c127a08997fe279f9e74d585c5b95983b4bf"
40
+ },
41
+ {
42
+ "path": "fixtures/v1/not-executed-receipt.json",
43
+ "sha256": "4582002c36cca422ac1ad9a5858558234d5ed162dbe72b36665fe09ab098099f"
44
+ },
45
+ {
46
+ "path": "fixtures/v1/privacy-redaction.json",
47
+ "sha256": "be4bae1d68db334875b3d198525dcd46f3efb46dbeea62de03399a915b716e20"
48
+ },
49
+ {
50
+ "path": "fixtures/v1/retry-identical.json",
51
+ "sha256": "41c944e15725d45a19bd97015c4bf7fb6ca1a4740426225426bc38799046bd8a"
52
+ },
53
+ {
54
+ "path": "fixtures/v1/stale-authority-reject.json",
55
+ "sha256": "700173546cff08486df201316472921d8304ea892c29770b5f199e63c92601b3"
56
+ },
57
+ {
58
+ "path": "fixtures/v1/structured-error-privacy-reject.json",
59
+ "sha256": "008186d22ed5048e4926c7b56c08a71802392886425944d0e1a22b10c7433d58"
60
+ },
61
+ {
62
+ "path": "fixtures/v1/structured-error-stripe-live-reject.json",
63
+ "sha256": "6e7e0d865ccab874fed66cefd15943bbaf51e4be37bfc99cd38f2e8cd6cafce6"
64
+ },
65
+ {
66
+ "path": "fixtures/v1/structured-error-stripe-test-reject.json",
67
+ "sha256": "ab9d748875e4688299a8678a551a2d3f13eb85c6f852ccbaaf102b870b3da82c"
68
+ },
69
+ {
70
+ "path": "fixtures/v1/unknown-advisory-roundtrip.json",
71
+ "sha256": "674e1dd9585d86ed7c8851a3d7e2b0ce81427a3dbc59c149409ee87375f9e879"
72
+ },
73
+ {
74
+ "path": "fixtures/v1/unknown-consequential-reject.json",
75
+ "sha256": "4228ce85d8f92d6eea61802fd34a410eab778314c70c8315cd1d9c9ba8ef2813"
76
+ },
77
+ {
78
+ "path": "fixtures/v1/valid-full.json",
79
+ "sha256": "2ba47dfcd5bc6dc4fae83160b05eeca480b51b065d251a0f531ca2c3effb0397"
80
+ },
81
+ {
82
+ "path": "fixtures/v1/valid-minimal.json",
83
+ "sha256": "e7d4e7d5cb11b4de809140d572c6f40a5ed4fc813f0044983930a6fbaab99444"
84
+ },
85
+ {
86
+ "path": "fixtures/v1/wrong-capability-digest.json",
87
+ "sha256": "8599acc3eebfba3883ec05e496cfc66e08e79877c8193c24db75540b4549062a"
88
+ },
89
+ {
90
+ "path": "schemas/v1/capability-manifest.schema.json",
91
+ "sha256": "8435c1ec9ebfd0f9b9b6d06f490dcfdac4696f002a83692899e1e172f17cd6dd"
92
+ },
93
+ {
94
+ "path": "schemas/v1/claim-request.schema.json",
95
+ "sha256": "eb9a6aa46c51550fa5505caeeff6e7773fce128e940fdb85a851cfd13cbf1375"
96
+ },
97
+ {
98
+ "path": "schemas/v1/context-packet.schema.json",
99
+ "sha256": "36f422011e03fafe07de5fb16a1e9c745015b4257f640e77f1ae1f4ba70971eb"
100
+ },
101
+ {
102
+ "path": "schemas/v1/delivery-receipt.schema.json",
103
+ "sha256": "1e505c9a790d2e5a3ccf1cd227b7a708924f9d92a61c2220964f7cb05a9d8f4c"
104
+ },
105
+ {
106
+ "path": "schemas/v1/feedback-report.schema.json",
107
+ "sha256": "6f9f272b831d30574ecf56601307a361544f022c7690fd8077aeae8ca5913e37"
108
+ },
109
+ {
110
+ "path": "schemas/v1/lease-receipt.schema.json",
111
+ "sha256": "e7b3c1f6857e4ebad930518236011b8346054b1fa7d38607def4a42c1ba9a739"
112
+ },
113
+ {
114
+ "path": "schemas/v1/monitor-event.schema.json",
115
+ "sha256": "df270f5b7e280c10293f2c964727d13baa0488c9e1cc87037ba1307bc76958dc"
116
+ },
117
+ {
118
+ "path": "schemas/v1/monitor-receipt.schema.json",
119
+ "sha256": "555dba3db355498a1813bfcf045fe2c3f10057789539918e3303c11191048b33"
120
+ },
121
+ {
122
+ "path": "schemas/v1/run-receipt.schema.json",
123
+ "sha256": "de55aca54248a208560fffade7bcfdc555e83daf330f37fe482bb8068495ece6"
124
+ },
125
+ {
126
+ "path": "schemas/v1/structured-error.schema.json",
127
+ "sha256": "ea8b6d40528634743efa91a550d27d8191adc8ce95e630356dadce98ba864d64"
128
+ },
129
+ {
130
+ "path": "schemas/v1/work-packet.schema.json",
131
+ "sha256": "82f149e5ceedf004a5c129f264d0cb94e6704a7eadae8f02dbd40a62b75a556c"
132
+ }
133
+ ]
134
+ }
@@ -0,0 +1 @@
1
+ {"fixture_id":"canonical-hash","input_ref":{"file":"contract-inputs.v1.json","schema_id":"forge.memory.work-packet.v1"},"operation":"canonical-hash","expected":{"stable_under_key_reordering":true,"content_hash_excluded":true}}