@haposoft/cafekit 0.18.0 → 0.18.1

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 (83) hide show
  1. package/README.md +1 -1
  2. package/bin/__tests__/codex-hooks.test.js +169 -236
  3. package/bin/__tests__/codex-native.test.js +54 -114
  4. package/bin/__tests__/develop-contract.test.js +101 -1361
  5. package/bin/__tests__/legacy-authority-decoupled.test.js +14 -19
  6. package/bin/__tests__/package-inventory.test.js +1 -395
  7. package/bin/__tests__/spec-narrowing.test.js +30 -134
  8. package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -372
  9. package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
  10. package/bin/__tests__/validator-grounding.test.js +17 -2929
  11. package/bin/lib/managed-writer.js +2 -3
  12. package/bin/phases/codex-runtime.js +6 -3
  13. package/bin/phases/copy-payload.js +13 -28
  14. package/bin/phases/omp-runtime.js +6 -3
  15. package/package.json +2 -3
  16. package/src/claude/agents/code-auditor.md +9 -6
  17. package/src/claude/agents/debugger.md +3 -9
  18. package/src/claude/agents/docs-keeper.md +4 -7
  19. package/src/claude/agents/git-ops.md +2 -4
  20. package/src/claude/agents/implementer.md +6 -7
  21. package/src/claude/agents/inspector.md +2 -0
  22. package/src/claude/agents/project-manager.md +2 -2
  23. package/src/claude/agents/spec-maker.md +4 -4
  24. package/src/claude/agents/test-runner.md +8 -11
  25. package/src/claude/agents/ui-ux-designer.md +0 -1
  26. package/src/claude/hooks/__tests__/spec-gate.test.js +170 -330
  27. package/src/claude/hooks/__tests__/spec-state-touched.test.js +26 -0
  28. package/src/claude/hooks/spec-gate.cjs +8 -63
  29. package/src/claude/hooks/spec-state.cjs +47 -38
  30. package/src/claude/migration-manifest.json +12 -7
  31. package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
  32. package/src/claude/output-styles/coding-level-1-junior.md +3 -3
  33. package/src/claude/output-styles/coding-level-2-mid.md +3 -3
  34. package/src/claude/output-styles/coding-level-3-senior.md +2 -2
  35. package/src/claude/output-styles/coding-level-4-lead.md +5 -5
  36. package/src/claude/output-styles/coding-level-5-god.md +6 -6
  37. package/src/claude/rules/ai-dev-rules.md +1 -2
  38. package/src/claude/rules/workflow.md +1 -1
  39. package/src/claude/scripts/spec-receipt.cjs +0 -114
  40. package/src/claude/scripts/spec-resolver.cjs +41 -457
  41. package/src/claude/scripts/workflow-policy.cjs +3 -1801
  42. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  43. package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
  44. package/src/claude/skills/code-review/SKILL.md +25 -108
  45. package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -7
  46. package/src/claude/skills/develop/SKILL.md +22 -70
  47. package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
  48. package/src/claude/skills/research/SKILL.md +24 -55
  49. package/src/claude/skills/sync/SKILL.md +12 -34
  50. package/src/claude/skills/sync/references/rebind-and-audit.md +2 -2
  51. package/src/claude/skills/test/SKILL.md +39 -123
  52. package/src/claude/skills/test/references/execution-strategy.md +11 -22
  53. package/src/claude/skills/ui-ux/SKILL.md +1 -1
  54. package/src/claude/skills/ui-ux-pro-max/SKILL.md +24 -79
  55. package/src/claude/skills/web-testing/SKILL.md +2 -20
  56. package/src/codex/hooks/lib/spec-receipt.cjs +2 -30
  57. package/src/codex/hooks/lib/spec-utils.cjs +6 -45
  58. package/src/codex/hooks/spec-gate.cjs +11 -68
  59. package/src/codex/hooks/spec-state.cjs +37 -41
  60. package/src/common/AGENTS.md +4 -10
  61. package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
  62. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
  63. package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
  64. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
  65. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
  66. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
  67. package/src/claude/hooks/lib/context.cjs +0 -527
  68. package/src/claude/hooks/lib/detect.cjs +0 -474
  69. package/src/claude/scripts/change-firewall.cjs +0 -1748
  70. package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
  71. package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
  72. package/src/claude/scripts/spec-final-state.cjs +0 -290
  73. package/src/claude/scripts/spec-ground.cjs +0 -650
  74. package/src/claude/scripts/spec-readiness.cjs +0 -425
  75. package/src/claude/scripts/spec-scaffold.cjs +0 -2317
  76. package/src/claude/scripts/spec-semantic-model.cjs +0 -396
  77. package/src/claude/scripts/validate-spec-output.cjs +0 -3914
  78. package/src/claude/skills/code-review/references/verification-gate.md +0 -41
  79. package/src/claude/skills/specs/templates/design.md +0 -82
  80. package/src/claude/skills/specs/templates/requirements-init.md +0 -8
  81. package/src/claude/skills/specs/templates/requirements.md +0 -42
  82. package/src/claude/skills/specs/templates/spec-state.json +0 -56
  83. package/src/claude/skills/specs/templates/task.md +0 -47
@@ -19,7 +19,6 @@ const LEGACY_FILES = [
19
19
  'semantic-review-authority.cjs',
20
20
  'task-scaffold-guard.cjs',
21
21
  ];
22
- const MIGRATION = /Legacy spec\.json closeout is no longer supported/;
23
22
 
24
23
  function inTempProject(run) {
25
24
  const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-decoupled-')));
@@ -122,26 +121,24 @@ function checkProcessFirst(kind) {
122
121
  });
123
122
  }
124
123
 
125
- function checkLegacyCloseout(kind) {
126
- for (const status of ['done', 'completed']) {
124
+ // CafeKit no longer reads spec.json packets: a leftover one, closed or mid-execution, never
125
+ // blocks Stop on its own, and beside a process-first packet the decision is that packet's alone.
126
+ function checkLegacyIgnored(kind) {
127
+ for (const legacy of [{ status: 'done' }, { status: 'completed' }, { status: 'in_progress', doneTask: true }]) {
127
128
  inTempProject((root) => {
128
- writeLegacy(root, { status });
129
+ writeLegacy(root, legacy);
129
130
  removeLegacyFiles(root);
130
- assert.match(blockReason(stopGate(root, kind)), MIGRATION, `${kind} ${status}`);
131
+ assert.equal(stopGate(root, kind), '', `${kind} ${legacy.status} legacy packet alone`);
132
+ writeProcessFirst(root, { receipt: false });
133
+ const reason = blockReason(stopGate(root, kind));
134
+ assert.match(reason, /missing_receipt/);
135
+ assert.doesNotMatch(reason, /task-R1-01-legacy\.md/);
136
+ writeProcessFirst(root, { receipt: true });
137
+ assert.equal(stopGate(root, kind), '', `${kind} ${legacy.status} legacy packet beside a proven process-first packet`);
131
138
  });
132
139
  }
133
140
  }
134
141
 
135
- function checkLegacyMidExecution(kind) {
136
- inTempProject((root) => {
137
- writeLegacy(root, { status: 'in_progress', doneTask: true });
138
- removeLegacyFiles(root);
139
- const reason = blockReason(stopGate(root, kind));
140
- assert.doesNotMatch(reason, MIGRATION);
141
- assert.match(reason, /task-R1-01-legacy\.md/);
142
- });
143
- }
144
-
145
142
  function checkSession(kind) {
146
143
  inTempProject((root) => {
147
144
  removeLegacyFiles(root);
@@ -151,9 +148,7 @@ function checkSession(kind) {
151
148
 
152
149
  test('claude gate passes and blocks process-first with and without the legacy files', () => checkProcessFirst('claude'));
153
150
  test('codex gate passes and blocks process-first with and without the legacy files', () => checkProcessFirst('codex'));
154
- test('claude gate blocks legacy 2.1 closeout with the migration message', () => checkLegacyCloseout('claude'));
155
- test('codex gate blocks legacy 2.1 closeout with the migration message', () => checkLegacyCloseout('codex'));
156
- test('claude gate still receipt-checks a legacy 2.1 packet mid-execution', () => checkLegacyMidExecution('claude'));
157
- test('codex gate still receipt-checks a legacy 2.1 packet mid-execution', () => checkLegacyMidExecution('codex'));
151
+ test('claude gate ignores a leftover legacy packet', () => checkLegacyIgnored('claude'));
152
+ test('codex gate ignores a leftover legacy packet', () => checkLegacyIgnored('codex'));
158
153
  test('claude session starts without the legacy files', () => checkSession('claude'));
159
154
  test('codex session starts without the legacy files', () => checkSession('codex'));
@@ -114,13 +114,6 @@ const REQUIRED_PAYLOAD = [
114
114
  'src/claude/scripts/workflow-policy.cjs',
115
115
  'src/claude/scripts/provenance.cjs',
116
116
  'src/claude/scripts/spec-receipt.cjs',
117
- 'src/claude/scripts/spec-ground.cjs',
118
- 'src/claude/scripts/spec-final-state.cjs',
119
- 'src/claude/scripts/spec-readiness.cjs',
120
- 'src/claude/scripts/spec-semantic-model.cjs',
121
- 'src/claude/scripts/validate-spec-output.cjs',
122
- 'src/claude/scripts/spec-authoring-validation.cjs',
123
- 'src/claude/scripts/spec-authoring-digest.cjs',
124
117
  'src/claude/scripts/generate-skill-catalog.cjs',
125
118
  'src/claude/rules/process-management.md',
126
119
  'src/claude/rules/review-audit-self-decision.md',
@@ -1522,13 +1515,11 @@ function assertInstalledProvenance(root, platform, fixture) {
1522
1515
  const policy = path.join(scripts, 'workflow-policy.cjs');
1523
1516
  const resolver = path.join(scripts, 'spec-resolver.cjs');
1524
1517
  const receipt = path.join(scripts, 'spec-receipt.cjs');
1525
- const finalState = path.join(scripts, 'spec-final-state.cjs');
1526
- const readiness = path.join(scripts, 'spec-readiness.cjs');
1527
1518
  const gate = path.join(
1528
1519
  root,
1529
1520
  platform === 'claude' ? '.claude/hooks/spec-gate.cjs' : '.codex/hooks/spec-gate.cjs'
1530
1521
  );
1531
- for (const file of [helper, policy, resolver, receipt, finalState, readiness]) {
1522
+ for (const file of [helper, policy, resolver, receipt]) {
1532
1523
  assert.equal(fs.existsSync(file), true, `${platform} installed file missing: ${file}`);
1533
1524
  }
1534
1525
  assert.equal(fs.existsSync(gate), true, `${platform} installed gate missing: ${gate}`);
@@ -1660,26 +1651,13 @@ function assertInstalledScripts(root, platform) {
1660
1651
  const scripts = path.join(root, RUNTIMES[platform].root, 'scripts');
1661
1652
  const policy = path.join(scripts, 'workflow-policy.cjs');
1662
1653
  const scanner = path.join(scripts, 'scan-staged-secrets.cjs');
1663
- const grounder = path.join(scripts, 'spec-ground.cjs');
1664
- const finalState = path.join(scripts, 'spec-final-state.cjs');
1665
- const readiness = path.join(scripts, 'spec-readiness.cjs');
1666
- const validator = path.join(scripts, 'validate-spec-output.cjs');
1667
1654
  assert.ok(fs.existsSync(policy), `installed policy missing: ${policy}`);
1668
1655
  assert.ok(fs.existsSync(scanner), `installed scanner missing: ${scanner}`);
1669
- assert.ok(fs.existsSync(grounder), `installed validator dependency missing: ${grounder}`);
1670
- assert.ok(fs.existsSync(finalState), `installed final-state dependency missing: ${finalState}`);
1671
- assert.ok(fs.existsSync(readiness), `installed readiness finalizer missing: ${readiness}`);
1672
- assert.ok(fs.existsSync(validator), `installed validator missing: ${validator}`);
1673
1656
 
1674
1657
  const policyRun = spawnSync(process.execPath, [policy, '--json'], { cwd: root, encoding: 'utf8' });
1675
1658
  assert.equal(policyRun.status, 0, `${policyRun.stdout}\n${policyRun.stderr}`);
1676
1659
  assert.equal(JSON.parse(policyRun.stdout).contract, 'execution-policy');
1677
1660
 
1678
- const validatorRun = spawnSync(process.execPath, [validator], { cwd: root, encoding: 'utf8' });
1679
- assert.equal(validatorRun.status, 2, `${validatorRun.stdout}\n${validatorRun.stderr}`);
1680
- assert.match(validatorRun.stderr, /Usage: .*validate-spec-output\.cjs/);
1681
- assert.doesNotMatch(validatorRun.stderr, /MODULE_NOT_FOUND|Cannot find module/);
1682
-
1683
1661
  const safe = path.join(root, 'safe.txt');
1684
1662
  fs.writeFileSync(safe, 'mode=safe\n');
1685
1663
  spawnSync('git', ['init', '-q'], { cwd: root });
@@ -1689,347 +1667,10 @@ function assertInstalledScripts(root, platform) {
1689
1667
  assert.match(scannerRun.stdout, /No staged secrets found/);
1690
1668
  }
1691
1669
 
1692
- function installedSemanticPaths(root, platform) {
1693
- const runtimeRoot = path.join(root, RUNTIMES[platform].root);
1694
- const skillRoot = platform === 'codex'
1695
- ? path.join(root, '.agents', 'skills')
1696
- : path.join(runtimeRoot, 'skills');
1697
- const paths = {
1698
- policy: path.join(runtimeRoot, 'scripts', 'workflow-policy.cjs'),
1699
- scaffold: path.join(runtimeRoot, 'scripts', 'spec-scaffold.cjs'),
1700
- validator: path.join(runtimeRoot, 'scripts', 'validate-spec-output.cjs'),
1701
- authoringValidator: path.join(runtimeRoot, 'scripts', 'spec-authoring-validation.cjs'),
1702
- authoringDigest: path.join(runtimeRoot, 'scripts', 'spec-authoring-digest.cjs'),
1703
- grounder: path.join(runtimeRoot, 'scripts', 'spec-ground.cjs'),
1704
- finalState: path.join(runtimeRoot, 'scripts', 'spec-final-state.cjs'),
1705
- readiness: path.join(runtimeRoot, 'scripts', 'spec-readiness.cjs'),
1706
- semanticModel: path.join(runtimeRoot, 'scripts', 'spec-semantic-model.cjs'),
1707
- resolver: path.join(runtimeRoot, 'scripts', 'spec-resolver.cjs'),
1708
- provenance: path.join(runtimeRoot, 'scripts', 'provenance.cjs'),
1709
- stateTemplate: path.join(skillRoot, 'specs', 'templates', 'spec-state.json'),
1710
- };
1711
- for (const [name, target] of Object.entries(paths)) {
1712
- assert.equal(fs.existsSync(target), true, `${platform} installed ${name} missing: ${target}`);
1713
- assert.equal(path.relative(root, target).startsWith('..'), false, `${platform} ${name} escaped install root`);
1714
- }
1715
- return paths;
1716
- }
1717
-
1718
- function runInstalled(script, args, root, expected = 0) {
1719
- const result = spawnSync(process.execPath, [script, ...args], { cwd: root, encoding: 'utf8' });
1720
- assert.equal(result.status, expected, `${script}\n${result.stdout}\n${result.stderr}`);
1721
- return result;
1722
- }
1723
-
1724
1670
  function writeJson(target, value) {
1725
1671
  fs.writeFileSync(target, `${JSON.stringify(value, null, 2)}\n`);
1726
1672
  }
1727
1673
 
1728
- function materializeSpecState(paths, root, feature, { strict = false } = {}) {
1729
- const featureDir = path.join(root, 'specs', feature);
1730
- runInstalled(paths.scaffold, [feature], root);
1731
- const state = JSON.parse(fs.readFileSync(path.join(featureDir, 'spec.json'), 'utf8'));
1732
- state.scope_lock.in_scope = [`${feature} behavior`];
1733
- state.scope_lock.out_of_scope = ['unrelated behavior'];
1734
- if (strict) {
1735
- state.workflow_policy.assurance_level = 'Strict';
1736
- state.workflow_policy.classified_minimum.assurance_level = 'Strict';
1737
- state.workflow_policy.risks = ['auth'];
1738
- }
1739
- writeJson(path.join(featureDir, 'spec.json'), state);
1740
- return { featureDir, specFile: path.join(featureDir, 'spec.json'), state };
1741
- }
1742
-
1743
- function requirementsProjection({ proof = false } = {}) {
1744
- return `# Requirements
1745
-
1746
- ## Requirements
1747
-
1748
- ### Requirement 1: Installed behavior
1749
-
1750
- - **R1.1**: The CommonJS entrypoint \`src/entry.js\` shall return an object containing only status \`enabled\` when its sole \`valid\` argument is the boolean \`true\`; it shall return an object containing only status \`rejected\` for \`false\`, a missing argument, or any non-boolean value.${proof ? '\n- **R1.2**: The installed verifier shall prove the observed entry behavior through its grounded evidence boundary.' : ''}
1751
- `;
1752
- }
1753
-
1754
- const TYPED_ANCHOR_COLUMNS = ['ID', 'Type', 'Target', 'Role', 'Access', 'Action'];
1755
-
1756
- function typedAnchorTable(rows) {
1757
- assert.ok(Array.isArray(rows) && rows.length > 0, 'typed anchor projection requires rows');
1758
- const header = `| ${TYPED_ANCHOR_COLUMNS.join(' | ')} |`;
1759
- const separator = `|${TYPED_ANCHOR_COLUMNS.map(() => '---').join('|')}|`;
1760
- const body = rows.map((row) => {
1761
- assert.deepEqual(Object.keys(row), ['id', 'type', 'target', 'role', 'access', 'action']);
1762
- assert.ok(Object.values(row).every((value) => typeof value === 'string' && value.trim() !== ''));
1763
- return `| ${row.id} | ${row.type} | \`${row.target}\` | ${row.role} | ${row.access} | ${row.action} |`;
1764
- });
1765
- return [header, separator, ...body].join('\n');
1766
- }
1767
-
1768
- function designProjection({
1769
- expected = 'exit 0; boolean true returns the exact enabled object; false, undefined, null, `"true"`, 1, and an object return the exact rejected object',
1770
- taskful = false,
1771
- } = {}) {
1772
- const anchors = typedAnchorTable([{
1773
- id: 'A-D-01', type: 'file', target: taskful ? 'src/design-boundary.js' : 'src/entry.js',
1774
- role: taskful ? 'existing design boundary for the entrypoint' : 'existing runtime entrypoint and contract owner',
1775
- access: 'read', action: 'read',
1776
- }]);
1777
- const reachabilityAnchors = taskful ? 'A-R1-01-01, A-R1-02-02' : 'A-D-01';
1778
- return `# Design
1779
-
1780
- ## Boundary
1781
-
1782
- - **Owns:** The exact return contract of the CommonJS function exported by \`src/entry.js\`.
1783
- - **Reads:** One \`valid\` argument; only the boolean \`true\` is valid.
1784
- - **Writes/exposes:** Exactly one status field whose value is \`enabled\` or \`rejected\`.
1785
- - **Outside boundary:** Unrelated runtime behavior.
1786
-
1787
- ## Typed Anchors
1788
-
1789
- ${anchors}
1790
-
1791
- ## Decisions and Invariants
1792
-
1793
- ### D1 — Installed result decision
1794
-
1795
- - **Decision:** \`valid === true\` returns an object containing only status \`enabled\`; every other value returns an object containing only status \`rejected\`.
1796
- - **Rejects ambiguity:** Truthy non-booleans such as \`"true"\` never count as valid.
1797
- - **Negative path:** \`false\`, \`undefined\`, \`null\`, strings, numbers, and objects return rejected.
1798
- - **Anchors:** A-D-01
1799
-
1800
- ### I1 — Rejection invariant
1801
-
1802
- Any input other than the boolean \`true\` never returns enabled.
1803
-
1804
- ### C1 — Result contract
1805
-
1806
- - **Owner:** A-D-01
1807
- - **Consumers:** \`test/entry.test.js\` and callers of the CommonJS export.
1808
- - **Shape/behavior:** The result is an object with exactly one \`status\` field set to \`enabled\` or \`rejected\`.
1809
- - **Compatibility:** The strict boolean discriminator, exact object shape, and two status values remain stable.
1810
-
1811
- ## Verification Definitions
1812
-
1813
- - **V1**: Criteria R1.1; Owner ${taskful ? 'R1-01' : 'A-D-01'}; ${taskful ? 'Proof criteria R1.2; Proof owner R1-02; Evidence anchor A-R1-02-02; ' : ''}Decision refs D1, I1, C1; Method command \`node --test test/entry.test.js\`; Expected ${expected}; Negative/failure \`false\`, missing input, \`null\`, and truthy non-booleans all return the exact rejected object; Reachability/grounding entrypoint \`src/entry.js\` via ${reachabilityAnchors}.
1814
- `;
1815
- }
1816
-
1817
- function completeSemanticReview(paths, root, fixture, counterexamples) {
1818
- // C16/D13: only the installed spec-authoring-validation.cjs coordinator may
1819
- // flip authoring.* to validated and write the matching receipt (I21/R3.9) —
1820
- // run it over the fixture's current bytes instead of hand-writing the enum.
1821
- // Lifecycle order (I15/R3.7): authoring -> coordinator -> semantic review ->
1822
- // readiness, never the reverse.
1823
- runInstalled(paths.scaffold, [fixture.state.feature_name, '--sync-semantic-model'], root);
1824
- runInstalled(paths.authoringValidator, [fixture.featureDir], root);
1825
- const state = JSON.parse(fs.readFileSync(fixture.specFile, 'utf8'));
1826
- fixture.reviewResult = {
1827
- verdict: 'PASS',
1828
- findings: [],
1829
- unresolved_decisions: [],
1830
- graph_coverage: [
1831
- 'criterion_local', 'cross_criterion', 'runtime_path',
1832
- 'assumption_provenance', 'compatibility_migration',
1833
- ].map((surface) => ({
1834
- surface, covered: true,
1835
- notes: 'The review covers this semantic surface against the canonical model.',
1836
- })),
1837
- reviewed_criteria: counterexamples.map(({ criterion }) => criterion),
1838
- counterexamples,
1839
- reviewer_evidence: null,
1840
- };
1841
- if (state.workflow_policy.assurance_level === 'Strict') {
1842
- const digest = runInstalled(paths.validator, [fixture.featureDir, '--semantic-digest'], root).stdout.trim();
1843
- assert.match(digest, /^sha256:[a-f0-9]{64}$/);
1844
- return digest;
1845
- }
1846
- const reviewFile = path.join(fixture.featureDir, '.review-result.json');
1847
- writeJson(reviewFile, fixture.reviewResult);
1848
- runInstalled(paths.readiness, [fixture.featureDir, '--review-result', reviewFile], root);
1849
- fs.unlinkSync(reviewFile);
1850
- runInstalled(paths.validator, [fixture.featureDir], root);
1851
- runInstalled(paths.grounder, [fixture.featureDir, '--root', root], root);
1852
- return JSON.parse(fs.readFileSync(fixture.specFile, 'utf8')).validation.semantic_review.semantic_digest;
1853
- }
1854
-
1855
- function createTasklessFixture(paths, root, feature, options = {}) {
1856
- fs.mkdirSync(path.join(root, 'src'), { recursive: true });
1857
- fs.mkdirSync(path.join(root, 'test'), { recursive: true });
1858
- fs.writeFileSync(path.join(root, 'src', 'entry.js'), 'module.exports = (valid) => ({ status: valid === true ? "enabled" : "rejected" });\n');
1859
- fs.writeFileSync(path.join(root, 'src', 'design-boundary.js'), 'module.exports = { entry: "src/entry.js" };\n');
1860
- fs.writeFileSync(path.join(root, 'test', 'entry.test.js'), `const test = require('node:test');
1861
- const assert = require('node:assert/strict');
1862
- const entry = require('../src/entry.js');
1863
-
1864
- test('entry accepts only the boolean true discriminator', () => {
1865
- assert.deepEqual(entry(true), { status: 'enabled' });
1866
- for (const invalid of [false, undefined, null, 'true', 1, {}]) {
1867
- assert.deepEqual(entry(invalid), { status: 'rejected' });
1868
- }
1869
- });
1870
- `);
1871
- fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({ scripts: { test: 'node --test' } }));
1872
- const fixture = materializeSpecState(paths, root, feature, options);
1873
- fs.writeFileSync(path.join(fixture.featureDir, 'requirements.md'), requirementsProjection());
1874
- fs.writeFileSync(path.join(fixture.featureDir, 'design.md'), designProjection());
1875
- fixture.digest = completeSemanticReview(paths, root, fixture, [{
1876
- criterion: 'R1.1', case_kind: 'failure',
1877
- scenario: 'The installed entry receives input without the required discriminator.',
1878
- expected: 'The installed entry returns rejected and never returns enabled.',
1879
- decision_refs: ['D1', 'I1', 'C1'], verification_ref: 'V1',
1880
- }]);
1881
- return fixture;
1882
- }
1883
-
1884
- function taskProjection({ id, title, ownedPath, criterion, verificationRef, role, artifact = false }) {
1885
- const artifactPath = `artifacts/${id}.json`;
1886
- const anchors = typedAnchorTable([
1887
- { id: `A-${id}-01`, type: 'file', target: ownedPath, role: 'owner', access: 'write', action: 'modify' },
1888
- ...(artifact ? [{
1889
- id: `A-${id}-02`, type: 'artifact', target: artifactPath,
1890
- role: 'verifier', access: 'write', action: 'create',
1891
- }] : []),
1892
- {
1893
- id: `A-${id}-${artifact ? '03' : '02'}`, type: 'command',
1894
- target: 'node --test test/entry.test.js', role: 'verifier', access: 'read', action: 'read',
1895
- },
1896
- ]);
1897
- return `# Task ${id}: ${title}
1898
- **Status:** pending
1899
-
1900
- ## Outcome
1901
-
1902
- Deliver observable ${title.toLowerCase()} behavior through the installed entrypoint.
1903
-
1904
- ## Scope
1905
-
1906
- - **In scope:** Exact behavior owned at ${ownedPath}.
1907
- - **Out of scope:** Unrelated runtime behavior.
1908
-
1909
- ## Anchors and Ownership
1910
-
1911
- ${anchors}
1912
-
1913
- ## Changes
1914
-
1915
- - [ ] Implement the exact owned behavior. _Requirements: ${criterion.slice(1)}_
1916
-
1917
- ## Acceptance
1918
-
1919
- - **${criterion}:** The installed command returns the criterion-specific observable state.
1920
-
1921
- ## Dependencies
1922
-
1923
- - none
1924
-
1925
- ## Verification Plan
1926
-
1927
- - **Verification ref:** ${verificationRef}
1928
- - **Task role:** ${role}
1929
- - **Command:** \`node --test test/entry.test.js\`
1930
- - **Expected:** Exit code 0 and the criterion-specific state is observed.${artifact ? ` The artifact \`${artifactPath}\` must exist, and SHA-256 over its current bytes must match the recorded digest.` : ''}
1931
- - **Negative path:** Invalid input returns the named rejected state.
1932
- - **Reachability:** \`src/entry.js\` is reached by the installed test command.
1933
- `;
1934
- }
1935
-
1936
- function createTaskFixture(paths, root, feature) {
1937
- fs.mkdirSync(path.join(root, 'artifacts'), { recursive: true });
1938
- const fixture = materializeSpecState(paths, root, feature);
1939
- fs.writeFileSync(path.join(fixture.featureDir, 'requirements.md'), requirementsProjection({ proof: true }));
1940
- fs.writeFileSync(path.join(fixture.featureDir, 'design.md'), designProjection({
1941
- expected: 'exit 0, status enabled, and verifier artifact `artifacts/R1-02.json` whose SHA-256 over current bytes matches the recorded digest',
1942
- taskful: true,
1943
- }));
1944
- const taskOne = 'tasks/task-R1-01-implement.md';
1945
- const taskTwo = 'tasks/task-R1-02-verify.md';
1946
- fs.mkdirSync(path.join(fixture.featureDir, 'tasks'), { recursive: true });
1947
- fs.writeFileSync(path.join(fixture.featureDir, taskOne), taskProjection({
1948
- id: 'R1-01', title: 'Implement behavior', ownedPath: 'src/entry.js', criterion: 'R1.1',
1949
- verificationRef: 'V1', role: 'subject implements R1.1',
1950
- }));
1951
- fs.writeFileSync(path.join(fixture.featureDir, taskTwo), taskProjection({
1952
- id: 'R1-02', title: 'Verify behavior', ownedPath: 'test/entry.test.js', criterion: 'R1.2',
1953
- verificationRef: 'V1', role: 'verifier verifies V1 through separately owned R1.2 proof', artifact: true,
1954
- }));
1955
- const state = fixture.state;
1956
- state.authoring.tasks = 'draft';
1957
- state.task_files = [taskOne, taskTwo];
1958
- state.task_registry = Object.fromEntries([
1959
- [taskOne, { id: 'R1-01', title: 'Implement behavior', status: 'pending', dependencies: [], blocker: null, started_at: null, completed_at: null, last_updated_at: null }],
1960
- [taskTwo, { id: 'R1-02', title: 'Verify behavior', status: 'pending', dependencies: [], blocker: null, started_at: null, completed_at: null, last_updated_at: null }],
1961
- ]);
1962
- state.coordination.boundaries = [{
1963
- id: 'B-OWN', type: 'ownership', tasks: ['R1-01', 'R1-02'],
1964
- write_sets: { 'R1-01': ['src/entry.js'], 'R1-02': ['test/entry.test.js', 'artifacts/R1-02.json'] },
1965
- }, {
1966
- id: 'B-PROOF', type: 'proof', subject: 'R1-01', verifier: 'R1-02',
1967
- verification_ref: 'V1', artifact_anchor: 'A-R1-02-02',
1968
- }];
1969
- writeJson(fixture.specFile, state);
1970
- fixture.digest = completeSemanticReview(paths, root, fixture, [{
1971
- criterion: 'R1.1', case_kind: 'failure',
1972
- scenario: 'Invalid input reaches the installed implementation boundary.',
1973
- expected: 'The implementation returns rejected and never reports enabled.',
1974
- decision_refs: ['D1', 'I1', 'C1'], verification_ref: 'V1',
1975
- }, {
1976
- criterion: 'R1.2', case_kind: 'failure',
1977
- scenario: 'The verification command completes without producing its proof artifact.',
1978
- expected: 'The verification criterion remains unsatisfied until `artifacts/R1-02.json` exists and its SHA-256 over current bytes matches the recorded digest.',
1979
- decision_refs: ['D1', 'I1', 'C1'], verification_ref: 'V1',
1980
- }]);
1981
- return fixture;
1982
- }
1983
-
1984
- function initializeGit(root) {
1985
- fs.writeFileSync(path.join(root, '.gitignore'), `${'node_' + 'modules'}/\n`);
1986
- for (const args of [
1987
- ['init', '-q'], ['config', 'user.name', 'CafeKit Packed E2E'],
1988
- ['config', 'user.email', 'packed-e2e@example.invalid'],
1989
- ['add', '--', '.gitignore', 'src/entry.js', 'src/design-boundary.js', 'test/entry.test.js', 'package.json'],
1990
- ['commit', '--no-gpg-sign', '-qm', 'packed semantic fixture'],
1991
- ]) {
1992
- const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
1993
- assert.equal(result.status, 0, `${args.join(' ')}\n${result.stdout}\n${result.stderr}`);
1994
- }
1995
- }
1996
-
1997
- function assertStrictRefusedAsUnsupported(paths, root, fixture) {
1998
- const specFile = path.join(fixture.featureDir, 'spec.json');
1999
- const before = fs.readFileSync(specFile);
2000
- const reviewFile = path.join(root, 'strict-review.json');
2001
- fs.writeFileSync(reviewFile, JSON.stringify(fixture.reviewResult));
2002
- const result = spawnSync(process.execPath, [paths.readiness, fixture.featureDir, '--review-result', reviewFile], { cwd: root, encoding: 'utf8' });
2003
- fs.rmSync(reviewFile, { force: true });
2004
- assert.notEqual(result.status, 0, `${result.stdout}\n${result.stderr}`);
2005
- assert.match(`${result.stdout}\n${result.stderr}`, /Strict assurance is no longer supported/);
2006
- assert.equal(fs.readFileSync(specFile).equals(before), true, 'a refused Strict readiness must leave spec.json unchanged');
2007
- }
2008
-
2009
- function assertStaleDigestMutations(paths, root, taskless, taskBearing) {
2010
- const requirementFile = path.join(taskless.featureDir, 'requirements.md');
2011
- const requirementBytes = fs.readFileSync(requirementFile);
2012
- fs.appendFileSync(requirementFile, '\nThe installed Markdown meaning changed.\n');
2013
- assert.match(runInstalled(paths.validator, [taskless.featureDir], root, 1).stderr, /semantic_digest: stale/);
2014
- fs.writeFileSync(requirementFile, requirementBytes);
2015
-
2016
- const tasklessState = JSON.parse(fs.readFileSync(taskless.specFile, 'utf8'));
2017
- const originalPolicy = JSON.parse(JSON.stringify(tasklessState.workflow_policy));
2018
- tasklessState.workflow_policy.planning_depth = 'Full';
2019
- writeJson(taskless.specFile, tasklessState);
2020
- assert.match(runInstalled(paths.validator, [taskless.featureDir], root, 1).stderr, /semantic_digest: stale/);
2021
- tasklessState.workflow_policy = originalPolicy;
2022
- writeJson(taskless.specFile, tasklessState);
2023
-
2024
- const taskState = JSON.parse(fs.readFileSync(taskBearing.specFile, 'utf8'));
2025
- const originalId = taskState.coordination.boundaries[0].id;
2026
- taskState.coordination.boundaries[0].id = 'B-OWN-MUTATED';
2027
- writeJson(taskBearing.specFile, taskState);
2028
- assert.match(runInstalled(paths.validator, [taskBearing.featureDir], root, 1).stderr, /semantic_digest: stale/);
2029
- taskState.coordination.boundaries[0].id = originalId;
2030
- writeJson(taskBearing.specFile, taskState);
2031
- }
2032
-
2033
1674
  function assertTransforms(root, platform) {
2034
1675
  const skillRoot = path.join(
2035
1676
  root,
@@ -2745,41 +2386,6 @@ test('repository and package guides document adaptive Docs usage', () => {
2745
2386
  }
2746
2387
  });
2747
2388
 
2748
- test('packed Claude and Codex installs execute semantic kernel behavior without package source', () => {
2749
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-packed-semantic-'));
2750
- const destination = path.join(root, 'pack');
2751
- fs.mkdirSync(destination, { recursive: true });
2752
- try {
2753
- const packed = npmPack(['--pack-destination', destination, '--json'], PACKAGE_ROOT);
2754
- const tarball = path.join(destination, packed.filename);
2755
- const runtimeClosure = packedRuntimeClosure(path.join(root, 'runtime-closure'));
2756
- assertCleanInventory(packedInventory(tarball));
2757
-
2758
- for (const platform of ['claude', 'codex']) {
2759
- const project = path.join(root, platform);
2760
- const installer = installPacked(tarball, project, runtimeClosure);
2761
- runInstaller(installer, project, [platform], null);
2762
- const packedSource = path.resolve(path.dirname(installer), '..', 'src');
2763
- fs.rmSync(packedSource, { recursive: true, force: true });
2764
- assert.equal(fs.existsSync(packedSource), false, `${platform} package source must be unavailable`);
2765
-
2766
- const paths = installedSemanticPaths(project, platform);
2767
- const taskless = createTasklessFixture(paths, project, 'compact-installed');
2768
- initializeGit(project);
2769
-
2770
- const strict = createTasklessFixture(paths, project, 'strict-installed', { strict: true });
2771
- const taskBearing = createTaskFixture(paths, project, 'tasks-installed');
2772
- assertStrictRefusedAsUnsupported(paths, project, strict);
2773
- assertStaleDigestMutations(paths, project, taskless, taskBearing);
2774
- runInstalled(paths.validator, [taskless.featureDir], project);
2775
- runInstalled(paths.validator, [taskBearing.featureDir], project);
2776
- runInstalled(paths.grounder, [taskBearing.featureDir, '--root', project], project);
2777
- }
2778
- } finally {
2779
- fs.rmSync(root, { recursive: true, force: true });
2780
- }
2781
- });
2782
-
2783
2389
  test('packed Claude and Codex installs self-contain runtime provenance and fail closed without it', () => {
2784
2390
  const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cafekit-provenance-package-'));
2785
2391
  const destination = path.join(root, 'pack');