sneakoscope 0.9.18 → 0.9.19

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 (35) hide show
  1. package/README.md +9 -9
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/package.json +12 -2
  6. package/src/core/commands/scouts-command.mjs +22 -4
  7. package/src/core/feature-fixtures.mjs +28 -9
  8. package/src/core/feature-registry.mjs +20 -2
  9. package/src/core/fsx.mjs +1 -1
  10. package/src/core/pipeline/active-context.mjs +1 -1
  11. package/src/core/pipeline/pipeline-plan-writer.mjs +1 -1
  12. package/src/core/pipeline/plan-schema.mjs +1 -1
  13. package/src/core/pipeline/prompt-context.mjs +1 -1
  14. package/src/core/pipeline/route-prep.mjs +1 -1
  15. package/src/core/pipeline/scout-stage-policy.mjs +1 -1
  16. package/src/core/pipeline/stage-policy.mjs +1 -1
  17. package/src/core/pipeline/stop-gate.mjs +1 -1
  18. package/src/core/pipeline/validation.mjs +1 -1
  19. package/src/core/pipeline-internals/runtime-core.mjs +1693 -0
  20. package/src/core/pipeline-runtime.mjs +22 -1693
  21. package/src/core/scouts/engines/codex-app-subagent-engine.mjs +66 -5
  22. package/src/core/scouts/engines/codex-exec-parallel-engine.mjs +18 -4
  23. package/src/core/scouts/engines/scout-engine-base.mjs +5 -1
  24. package/src/core/scouts/engines/scout-engine-detect.mjs +7 -3
  25. package/src/core/scouts/engines/tmux-lane-cleanup.mjs +16 -0
  26. package/src/core/scouts/engines/tmux-lane-engine.mjs +72 -5
  27. package/src/core/scouts/engines/tmux-lane-watcher.mjs +26 -0
  28. package/src/core/scouts/scout-consensus.mjs +31 -0
  29. package/src/core/scouts/scout-output-fixtures.mjs +27 -0
  30. package/src/core/scouts/scout-output-normalizer.mjs +4 -0
  31. package/src/core/scouts/scout-output-parser.mjs +266 -0
  32. package/src/core/scouts/scout-output-validator.mjs +3 -0
  33. package/src/core/scouts/scout-readonly-guard.mjs +23 -2
  34. package/src/core/scouts/scout-runner.mjs +69 -11
  35. package/src/core/version.mjs +1 -1
package/README.md CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
  Fast legacy-free proof-first Codex trust layer with image-based Voxel TriWiki.
4
4
 
5
- Sneakoscope Codex (`sks`) is a Codex CLI/App harness that makes repeatable Codex work auditable. `0.9.18` makes route execution hermetic and evidence-strict: Five-Scout intake can use real Codex/tmux engines when available, route E2E runs in temp project roots, feature fixtures no longer receive implicit static-pass fallback, and pipeline planning is exposed through split policy modules with a facade compatibility layer.
5
+ Sneakoscope Codex (`sks`) is a Codex CLI/App harness that makes repeatable Codex work auditable. `0.9.19` binds real Scout engine output to structured `sks.scout-result.v1` evidence, keeps `pipeline-runtime.mjs` as a small compatibility facade, and release-gates packed npm/npx/global install behavior with explicit feature quality boundaries.
6
6
 
7
7
  ![Sneakoscope Codex architecture and pipeline](https://raw.githubusercontent.com/mandarange/Sneakoscope-Codex/dev/docs/assets/sneakoscope-architecture-pipeline.jpg)
8
8
 
9
- ## 0.9.18 Current Release
9
+ ## 0.9.19 Current Release
10
10
 
11
- 0.9.18 makes SKS route execution hermetic and evidence-strict. Five-Scout intake can run through real Codex/tmux engines when available, falls back honestly when not, and never claims speedup from mock/static evidence. E2E route tests run in isolated temp project roots. Feature fixtures no longer receive implicit static-pass fallback; every feature declares an explicit fixture. Pipeline architecture is split into stage policy, scout policy, prompt context, active context, and stop-gate modules.
11
+ 0.9.19 makes SKS Scout evidence parse-bound and package-install verified. Real Codex/tmux/Codex App subagent engines must write parseable scout output before consensus can use them as primary evidence. If an engine is unavailable or output cannot be parsed, SKS records a blocked or verified-partial result instead of substituting static evidence. Packed package checks now cover temp install, npx one-shot, and global shim behavior.
12
12
 
13
13
  Highlights:
14
14
 
15
- - Serious route mock/fixture commands call `maybeFinalizeRoute`, so Team, QA-LOOP, Research, PPT, Image UX Review, Computer Use, DB, Wiki, and GX fixtures produce route-local `completion-proof.json` without a separate repair/finalize step.
16
- - `sks scouts engines --json` reports Codex exec, tmux, Codex App subagent, local static, and sequential fallback availability with blockers.
17
- - Scout read-only guards snapshot source state and allow only mission-local `scout-*` artifacts plus scout reports.
18
- - E2E route tests run actual route commands inside isolated temp roots instead of sharing the source checkout `.sneakoscope`.
19
- - Feature fixtures execute deterministic allowlisted commands in hermetic temp roots and validate artifacts generated by those commands, including mission-local proof, visual ledgers, DB reports, and GX/Wiki evidence.
20
- - `npm run release:check` includes `pipeline-budget:check`, `scout-engines:check`, strict scout validation, and hermetic fixture execution.
15
+ - Real Scout outputs are parsed from pure JSON, fenced JSON, `SCOUT_RESULT_JSON:` markdown, or final JSON blocks into `sks.scout-result.v1`.
16
+ - `scout-consensus.json` records whether primary evidence came from parsed real outputs or local static fixtures.
17
+ - `tmux-lanes` has an opt-in session/window/watcher/cleanup path; release gates skip or block honestly when live tmux/Codex is unavailable.
18
+ - Codex App subagents require a local `sks.codex-app-subagents-capability.v1` descriptor; `SKS_CODEX_APP_SUBAGENTS=1` alone is not enough.
19
+ - `npm run release:check` includes `pipeline-runtime:check`, `feature-quality:check`, `scouts:parser-check`, and `blackbox:check`.
20
+ - Feature fixtures report `runtime_verified`, `runtime_mock_verified`, `integration_optional`, `static_contract`, and `missing` counts.
21
21
  - `sks rust status|smoke --json` reports optional Rust availability, detects stale native binaries, and proves JS fallback parity when native Rust is missing or version-mismatched.
22
22
  - `npm run release:check` includes `route-modularity:check`, `command-budget:check`, and `feature-fixtures:strict`.
23
23
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "0.9.18"
79
+ version = "0.9.19"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "0.9.18"
3
+ version = "0.9.19"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 0.9.18"),
7
+ Some("--version") => println!("sks-rs 0.9.19"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "0.9.18",
4
+ "version": "0.9.19",
5
5
  "description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
@@ -23,6 +23,9 @@
23
23
  "files": [
24
24
  "bin",
25
25
  "src",
26
+ "!src/core/pipeline/route-prep-*.mjs",
27
+ "!src/core/pipeline/prompt-context-*.mjs",
28
+ "!src/core/pipeline/stop-gate-*.mjs",
26
29
  "crates/sks-core/Cargo.lock",
27
30
  "crates/sks-core/Cargo.toml",
28
31
  "crates/sks-core/src",
@@ -44,13 +47,16 @@
44
47
  "route-modularity:check": "node ./scripts/check-route-modularity.mjs",
45
48
  "command-budget:check": "node ./scripts/check-command-module-budget.mjs",
46
49
  "pipeline-budget:check": "node ./scripts/check-pipeline-budget.mjs",
50
+ "pipeline-runtime:check": "node ./scripts/check-pipeline-runtime.mjs",
47
51
  "sizecheck": "node ./scripts/sizecheck.mjs",
48
52
  "registry:check": "node ./scripts/release-registry-check.mjs",
49
53
  "feature:check": "node ./bin/sks.mjs features check --json",
54
+ "feature-quality:check": "node ./scripts/check-feature-quality.mjs",
50
55
  "all-features:selftest": "node ./bin/sks.mjs all-features selftest --mock --json",
51
56
  "all-features:execute-fixtures": "node ./bin/sks.mjs all-features selftest --mock --execute-fixtures --strict-artifacts --json",
52
57
  "feature-fixtures:strict": "node ./bin/sks.mjs all-features selftest --mock --execute-fixtures --strict-artifacts --hermetic --json",
53
58
  "scout-engines:check": "node ./bin/sks.mjs scouts engines --json",
59
+ "scouts:parser-check": "node --test \"test/unit/scout-output-parser.test.mjs\"",
54
60
  "scouts:selftest": "node ./bin/sks.mjs scouts run latest --engine local-static --mock --json",
55
61
  "scouts:check": "node ./bin/sks.mjs scouts validate latest --strict --json",
56
62
  "perf:cold-start": "node ./bin/sks.mjs perf cold-start --json",
@@ -60,10 +66,14 @@
60
66
  "test:integration:mock": "node --test \"test/integration/**/*.test.mjs\"",
61
67
  "test:e2e:mock": "node --test \"test/e2e/**/*.test.mjs\"",
62
68
  "test:real-scouts": "node --test \"test/real/**/*.test.mjs\"",
69
+ "blackbox:pack-install": "node ./scripts/blackbox-pack-install.mjs",
70
+ "blackbox:npx": "node ./scripts/blackbox-npx-one-shot.mjs",
71
+ "blackbox:global-shim": "node ./scripts/blackbox-global-shim.mjs",
72
+ "blackbox:check": "npm run blackbox:pack-install && npm run blackbox:npx && npm run blackbox:global-shim",
63
73
  "rust:check": "cargo check --manifest-path crates/sks-core/Cargo.toml",
64
74
  "rust:smoke": "node ./scripts/rust-smoke.mjs",
65
75
  "coverage": "node --experimental-test-coverage --test \"test/**/*.test.mjs\"",
66
- "release:check": "npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-free:check && npm run route-modularity:check && npm run command-budget:check && npm run pipeline-budget:check && npm run packcheck && npm run feature:check && npm run all-features:selftest && npm run scout-engines:check && npm run scouts:selftest && npm run scouts:check && npm run feature-fixtures:strict && npm run selftest && npm run test:unit && npm run test:integration:mock && npm run test:e2e:mock && npm run rust:check && npm run rust:smoke && npm run perf:gate && npm run sizecheck && npm run registry:check",
76
+ "release:check": "npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-free:check && npm run route-modularity:check && npm run command-budget:check && npm run pipeline-budget:check && npm run pipeline-runtime:check && npm run packcheck && npm run feature:check && npm run feature-quality:check && npm run all-features:selftest && npm run scout-engines:check && npm run scouts:parser-check && npm run scouts:selftest && npm run scouts:check && npm run feature-fixtures:strict && npm run selftest && npm run test:unit && npm run test:integration:mock && npm run test:e2e:mock && npm run rust:check && npm run rust:smoke && npm run perf:gate && npm run blackbox:check && npm run sizecheck && npm run registry:check",
67
77
  "publish:dry": "npm run release:check && npm --cache /tmp/sks-npm-cache publish --dry-run --registry https://registry.npmjs.org/ --access public",
68
78
  "publish:npm": "npm --cache /tmp/sks-npm-cache publish --registry https://registry.npmjs.org/ --access public",
69
79
  "prepublishOnly": "npm run release:check && node ./scripts/release-registry-check.mjs --require-unpublished"
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { exists, projectRoot, readJson, writeJsonAtomic } from '../fsx.mjs';
2
+ import { ensureDir, exists, projectRoot, readJson, writeJsonAtomic } from '../fsx.mjs';
3
3
  import { createMission, loadMission, missionDir, setCurrent, stateFile } from '../mission.mjs';
4
4
  import { routePrompt } from '../routes.mjs';
5
5
  import { buildScoutTeamPlan, normalizeScoutPolicy, routeRequiresScoutIntake, scoutRouteLabel } from '../scouts/scout-plan.mjs';
@@ -181,18 +181,36 @@ export async function scoutsCommand(args = []) {
181
181
  });
182
182
  const sequentialMs = Number(sequentialRun.performance?.duration_ms || 0);
183
183
  const parallelMs = Number(parallelRun.performance?.duration_ms || 0);
184
+ const parsedRealOutputs = Number(parallelRun.consensus?.source_policy?.counts?.parsed_scout_output || 0);
185
+ const speedup = selection.real_parallel && parallelMs > 0 ? Number((sequentialMs / parallelMs).toFixed(2)) : null;
186
+ const claimAllowed = selection.real_parallel === true
187
+ && parsedRealOutputs === SCOUT_COUNT
188
+ && parallelRun.performance?.claim_allowed === true
189
+ && speedup > 1.1
190
+ && parallelRun.gate?.read_only_guard === true
191
+ && !parallelRun.gate?.blockers?.length;
184
192
  const result = {
185
- schema: 'sks.scout-benchmark.v1',
193
+ schema: 'sks.scout-benchmark.v2',
194
+ mission_id: id,
186
195
  engine: selection.selected,
187
196
  real_parallel: selection.real_parallel === true,
197
+ parsed_real_outputs: parsedRealOutputs,
188
198
  sequential_ms: sequentialMs,
189
199
  parallel_ms: parallelMs,
190
- speedup: selection.real_parallel && parallelMs > 0 ? Number((sequentialMs / parallelMs).toFixed(2)) : null,
191
- claim_allowed: selection.real_parallel === true && parallelRun.performance?.claim_allowed === true,
200
+ speedup,
201
+ claim_allowed: claimAllowed,
192
202
  confidence: selection.real_parallel ? 'medium' : 'low',
203
+ read_only_guard: parallelRun.gate?.read_only_guard === true ? 'passed' : 'blocked',
193
204
  notes: selection.real_parallel ? [] : ['mock/static benchmarks cannot claim real speedup']
194
205
  };
195
206
  await writeJsonAtomic(path.join(dir, 'scout-benchmark.json'), result);
207
+ const reportDir = path.join(root, '.sneakoscope', 'reports');
208
+ await ensureDir(reportDir);
209
+ await writeJsonAtomic(path.join(reportDir, 'scout-benchmark-summary.json'), {
210
+ schema: 'sks.scout-benchmark-summary.v1',
211
+ updated_at: new Date().toISOString(),
212
+ latest: result
213
+ });
196
214
  if (json) return console.log(JSON.stringify(result, null, 2));
197
215
  console.log(`Scout benchmark: ${result.claim_allowed ? 'claim allowed' : 'claim not allowed'}`);
198
216
  return;
@@ -1,4 +1,11 @@
1
1
  export const FEATURE_FIXTURE_SCHEMA = 'sks.feature-fixtures.v1';
2
+ export const FEATURE_QUALITY_LEVELS = Object.freeze([
3
+ 'runtime_verified',
4
+ 'runtime_mock_verified',
5
+ 'integration_optional',
6
+ 'static_contract',
7
+ 'missing'
8
+ ]);
2
9
 
3
10
  const FIXTURES = Object.freeze({
4
11
  'cli-help': fixture('static', 'sks help', [], 'pass'),
@@ -53,8 +60,8 @@ const FIXTURES = Object.freeze({
53
60
  'route-image-ux-review': fixture('execute_and_validate_artifacts', 'sks image-ux-review fixture --mock --json', ['completion-proof.json', { path: 'image-voxel-ledger.json', schema: 'sks.image-voxel-ledger.v1' }, 'image-ux-generated-review-ledger.json'], 'pass'),
54
61
  'route-computer-use': fixture('execute_and_validate_artifacts', 'sks computer-use import-fixture --mock --json', ['computer-use-evidence-ledger.json', { path: 'image-voxel-ledger.json', schema: 'sks.image-voxel-ledger.v1' }, 'completion-proof.json'], 'pass'),
55
62
  'route-cu': fixture('mock', '$CU mock evidence ledger', ['computer-use-evidence-ledger.json', 'image-voxel-ledger.json', 'completion-proof.json'], 'pass'),
56
- 'route-dfix': fixture('static', '$DFix tiny edit route policy', ['completion-proof.json'], 'pass'),
57
- 'route-answer': fixture('static', '$Answer answer-only route policy', [], 'pass'),
63
+ 'route-dfix': fixture('mock', '$DFix tiny edit route policy', ['completion-proof.json'], 'pass'),
64
+ 'route-answer': fixture('mock', '$Answer answer-only route policy', [], 'pass'),
58
65
  'route-goal': fixture('mock', '$Goal bridge route', ['goal-workflow.json', 'completion-proof.json'], 'pass'),
59
66
  'route-autoresearch': fixture('mock', '$AutoResearch fixture route', ['research-gate.json', 'completion-proof.json'], 'pass'),
60
67
  'route-mad-sks': fixture('mock', '$MAD-SKS permission gate route', ['mad-sks-gate.json', 'completion-proof.json'], 'pass'),
@@ -63,6 +70,10 @@ const FIXTURES = Object.freeze({
63
70
  'route-db': fixture('execute_and_validate_artifacts', 'sks db check --sql "SELECT 1" --json', ['completion-proof.json', 'db-operation-report.json'], 'pass'),
64
71
  'route-wiki': fixture('execute_and_validate_artifacts', 'sks wiki image-ingest test/fixtures/images/one-by-one.png --json', [{ path: 'completion-proof.json', schema: 'sks.completion-proof.v1' }, { path: 'image-voxel-ledger.json', schema: 'sks.image-voxel-ledger.v1' }], 'pass'),
65
72
  'route-gx': fixture('execute_and_validate_artifacts', 'sks gx validate fixture --mock --json', ['completion-proof.json', { path: 'image-voxel-ledger.json', schema: 'sks.image-voxel-ledger.v1' }, 'gx-validation.json'], 'pass'),
73
+ 'route-sks': fixture('mock', '$SKS control-surface route', ['completion-proof.json'], 'pass'),
74
+ 'route-help': fixture('mock', '$Help lightweight route', [], 'pass'),
75
+ 'route-commit': fixture('mock', '$Commit git route', ['completion-proof.json'], 'pass'),
76
+ 'route-commit-and-push': fixture('mock', '$Commit-And-Push git route', ['completion-proof.json'], 'pass'),
66
77
  'route-five-scout-intake': fixture('mock', 'sks scouts validate latest --strict --json', ['scout-team-plan.json', 'scout-consensus.json', 'scout-handoff.md', 'scout-gate.json'], 'pass'),
67
78
  'proof-scout-evidence': fixture('mock', 'sks team "fixture" --mock --json', ['completion-proof.json', 'scout-gate.json'], 'pass')
68
79
  });
@@ -92,11 +103,7 @@ const STATIC_CONTRACT_FEATURES = new Set([
92
103
  'handler-cu',
93
104
  'handler-dollars',
94
105
  'handler-mad-sks',
95
- 'handler-postinstall',
96
- 'route-sks',
97
- 'route-commit',
98
- 'route-commit-and-push',
99
- 'route-help'
106
+ 'handler-postinstall'
100
107
  ]);
101
108
 
102
109
  export function fixtureForFeature(featureId) {
@@ -119,15 +126,19 @@ export function fixtureForFeature(featureId) {
119
126
 
120
127
  export function fixtureSummary(features = []) {
121
128
  const counts = {};
129
+ const quality_counts = Object.fromEntries(FEATURE_QUALITY_LEVELS.map((level) => [level, 0]));
122
130
  const missing = [];
123
131
  for (const feature of features) {
124
132
  const status = feature.fixture?.status || 'missing';
125
133
  counts[status] = (counts[status] || 0) + 1;
134
+ const quality = feature.fixture?.quality || 'missing';
135
+ quality_counts[quality] = (quality_counts[quality] || 0) + 1;
126
136
  if (!feature.fixture) missing.push(feature.id);
127
137
  }
128
138
  return {
129
139
  schema: FEATURE_FIXTURE_SCHEMA,
130
140
  counts,
141
+ quality_counts,
131
142
  missing,
132
143
  ok: missing.length === 0 && !counts.missing
133
144
  };
@@ -142,7 +153,7 @@ export function validateFeatureFixtures(features = []) {
142
153
  continue;
143
154
  }
144
155
  if (!['contract', 'execute', 'execute_and_validate_artifacts', 'mock', 'static', 'real_optional', 'not_available'].includes(fx.kind)) blockers.push(`${feature.id}:fixture_kind`);
145
- if (!['real_optional', 'execute_and_validate_artifacts', 'execute', 'mock', 'static_contract', 'missing'].includes(fx.quality)) blockers.push(`${feature.id}:fixture_quality`);
156
+ if (!FEATURE_QUALITY_LEVELS.includes(fx.quality)) blockers.push(`${feature.id}:fixture_quality`);
146
157
  if (!['pass', 'missing', 'blocked', 'not_required'].includes(fx.status)) blockers.push(`${feature.id}:fixture_status`);
147
158
  if ((fx.kind === 'mock' || fx.kind === 'static') && !fx.command && fx.status !== 'not_required') blockers.push(`${feature.id}:fixture_command`);
148
159
  if (!Array.isArray(fx.expected_artifacts)) blockers.push(`${feature.id}:fixture_expected_artifacts`);
@@ -151,7 +162,7 @@ export function validateFeatureFixtures(features = []) {
151
162
  }
152
163
 
153
164
  function fixture(kind, command, expected_artifacts, status, extra = {}) {
154
- const quality = extra.quality || (kind === 'static' ? 'static_contract' : kind);
165
+ const quality = extra.quality || qualityForKind(kind);
155
166
  const rootMode = extra.root_mode || (kind === 'execute_and_validate_artifacts' || kind === 'execute' || kind === 'mock' ? 'hermetic_temp_project' : 'source_checkout_required');
156
167
  return {
157
168
  kind,
@@ -165,3 +176,11 @@ function fixture(kind, command, expected_artifacts, status, extra = {}) {
165
176
  ...extra
166
177
  };
167
178
  }
179
+
180
+ function qualityForKind(kind) {
181
+ if (kind === 'execute' || kind === 'execute_and_validate_artifacts') return 'runtime_verified';
182
+ if (kind === 'mock') return 'runtime_mock_verified';
183
+ if (kind === 'real_optional') return 'integration_optional';
184
+ if (kind === 'not_available') return 'missing';
185
+ return 'static_contract';
186
+ }
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { spawnSync } from 'node:child_process';
4
4
  import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS } from './routes.mjs';
5
- import { fixtureForFeature, fixtureSummary, validateFeatureFixtures } from './feature-fixtures.mjs';
5
+ import { FEATURE_QUALITY_LEVELS, fixtureForFeature, fixtureSummary, validateFeatureFixtures } from './feature-fixtures.mjs';
6
6
  import { runFeatureFixture, writeFeatureFixtureReports } from './feature-fixture-runner.mjs';
7
7
  import { exists, nowIso, packageRoot, readJson, readText, runProcess, writeTextAtomic } from './fsx.mjs';
8
8
 
@@ -68,6 +68,7 @@ export async function buildFeatureRegistry({ root = packageRoot(), generatedAt =
68
68
  },
69
69
  features,
70
70
  fixture_summary: fixtureSummary(features),
71
+ feature_quality_summary: featureQualitySummary(features),
71
72
  source_inventory: {
72
73
  cli_command_names: COMMAND_CATALOG.map((entry) => entry.name),
73
74
  handler_keys: handlerKeys,
@@ -125,7 +126,8 @@ export function validateFeatureRegistry(registry = {}) {
125
126
  'feature fixtures remain progressive',
126
127
  'registry proves coverage, not full roadmap completion'
127
128
  ],
128
- fixture_summary: fixtureSummary(features)
129
+ fixture_summary: fixtureSummary(features),
130
+ feature_quality_summary: featureQualitySummary(features)
129
131
  };
130
132
  }
131
133
 
@@ -149,6 +151,8 @@ export function buildAllFeaturesSelftest(registry, opts = {}) {
149
151
  checkRow('voxel_triwiki_contracts_present', registry.features.every((feature) => Boolean(feature.voxel_triwiki_integration)), missingFeatureField(registry, 'voxel_triwiki_integration')),
150
152
  checkRow('failure_contracts_present', registry.features.every((feature) => Array.isArray(feature.known_gaps)), missingFeatureField(registry, 'known_gaps')),
151
153
  checkRow('fixture_contracts_present', fixtures.ok, fixtures.blockers),
154
+ checkRow('feature_quality_levels_present', FEATURE_QUALITY_LEVELS.every((level) => Object.hasOwn(fixturesSummary.quality_counts || {}, level)), FEATURE_QUALITY_LEVELS),
155
+ checkRow('runtime_routes_not_static_contract', runtimeRoutesNotStaticContract(registry.features || []).ok, runtimeRoutesNotStaticContract(registry.features || []).blockers),
152
156
  checkRow('fixture_fallback_removed', registry.features.every((feature) => feature.fixture?.fallback_removed === true && feature.fixture?.status !== 'missing'), registry.features.filter((feature) => feature.fixture?.fallback_removed !== true || feature.fixture?.status === 'missing').map((feature) => feature.id)),
153
157
  checkRow('proof_fixture_contract_present', registry.features.some((feature) => feature.id === 'cli-proof' && feature.fixture?.status === 'pass'), ['cli-proof']),
154
158
  checkRow('voxel_fixture_contract_present', registry.features.some((feature) => feature.id === 'cli-wiki' && feature.fixture?.expected_artifacts?.some((artifact) => expectedArtifactPath(artifact).includes('image-voxel-ledger'))), ['cli-wiki']),
@@ -169,6 +173,7 @@ export function buildAllFeaturesSelftest(registry, opts = {}) {
169
173
  status: ok ? 'verified_partial' : 'blocked',
170
174
  checks,
171
175
  fixtures: fixturesSummary,
176
+ feature_quality_summary: featureQualitySummary(registry.features || []),
172
177
  coverage,
173
178
  executable_fixtures: executable,
174
179
  note: opts.executeFixtures
@@ -297,6 +302,7 @@ export function renderFeatureInventoryMarkdown(registry) {
297
302
  `- App skill aliases: ${coverage.counts.app_skill_aliases}`,
298
303
  `- Skills: ${coverage.counts.skills}`,
299
304
  `- Fixture statuses: ${Object.entries(fixtureSummary(registry.features).counts).map(([status, count]) => `${status}=${count}`).join(', ')}`,
305
+ `- Feature quality: ${Object.entries(fixtureSummary(registry.features).quality_counts).map(([quality, count]) => `${quality}=${count}`).join(', ')}`,
300
306
  '',
301
307
  '## Release Coverage Rule',
302
308
  '',
@@ -649,6 +655,18 @@ function checkRow(id, ok, blockers = []) {
649
655
  return { id, ok: Boolean(ok), blockers: ok ? [] : blockers };
650
656
  }
651
657
 
658
+ export function featureQualitySummary(features = []) {
659
+ return fixtureSummary(features).quality_counts;
660
+ }
661
+
662
+ export function runtimeRoutesNotStaticContract(features = []) {
663
+ const blockers = features
664
+ .filter((feature) => feature.category === 'route' || String(feature.id || '').startsWith('route-'))
665
+ .filter((feature) => feature.fixture?.quality === 'static_contract')
666
+ .map((feature) => `${feature.id}:static_contract`);
667
+ return { ok: blockers.length === 0, blockers };
668
+ }
669
+
652
670
  function missingFeatureField(registry, field) {
653
671
  return (registry.features || []).filter((feature) => !feature[field]).map((feature) => feature.id);
654
672
  }
package/src/core/fsx.mjs CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import crypto from 'node:crypto';
6
6
  import { spawn } from 'node:child_process';
7
7
 
8
- export const PACKAGE_VERSION = '0.9.18';
8
+ export const PACKAGE_VERSION = '0.9.19';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
 
@@ -1,3 +1,3 @@
1
1
  export {
2
2
  activeRouteContext
3
- } from '../pipeline-runtime.mjs';
3
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -5,4 +5,4 @@ export {
5
5
  buildPipelinePlan,
6
6
  writePipelinePlan,
7
7
  validatePipelinePlan
8
- } from '../pipeline-runtime.mjs';
8
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -1,4 +1,4 @@
1
1
  export {
2
2
  PIPELINE_PLAN_ARTIFACT,
3
3
  PIPELINE_PLAN_SCHEMA_VERSION
4
- } from '../pipeline-runtime.mjs';
4
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -3,4 +3,4 @@ export {
3
3
  dfixQuickContext,
4
4
  answerOnlyContext,
5
5
  computerUseFastContext
6
- } from '../pipeline-runtime.mjs';
6
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -1,3 +1,3 @@
1
1
  export {
2
2
  prepareRoute
3
- } from '../pipeline-runtime.mjs';
3
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -1,4 +1,4 @@
1
1
  export {
2
2
  buildPipelinePlan,
3
3
  validatePipelinePlan
4
- } from '../pipeline-runtime.mjs';
4
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -1,4 +1,4 @@
1
1
  export {
2
2
  buildPipelinePlan,
3
3
  validatePipelinePlan
4
- } from '../pipeline-runtime.mjs';
4
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -7,4 +7,4 @@ export {
7
7
  hasContext7DocsEvidence,
8
8
  projectGateStatus,
9
9
  evaluateStop
10
- } from '../pipeline-runtime.mjs';
10
+ } from '../pipeline-internals/runtime-core.mjs';
@@ -1,3 +1,3 @@
1
1
  export {
2
2
  validatePipelinePlan
3
- } from '../pipeline-runtime.mjs';
3
+ } from '../pipeline-internals/runtime-core.mjs';