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.
- package/README.md +9 -9
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/package.json +12 -2
- package/src/core/commands/scouts-command.mjs +22 -4
- package/src/core/feature-fixtures.mjs +28 -9
- package/src/core/feature-registry.mjs +20 -2
- package/src/core/fsx.mjs +1 -1
- package/src/core/pipeline/active-context.mjs +1 -1
- package/src/core/pipeline/pipeline-plan-writer.mjs +1 -1
- package/src/core/pipeline/plan-schema.mjs +1 -1
- package/src/core/pipeline/prompt-context.mjs +1 -1
- package/src/core/pipeline/route-prep.mjs +1 -1
- package/src/core/pipeline/scout-stage-policy.mjs +1 -1
- package/src/core/pipeline/stage-policy.mjs +1 -1
- package/src/core/pipeline/stop-gate.mjs +1 -1
- package/src/core/pipeline/validation.mjs +1 -1
- package/src/core/pipeline-internals/runtime-core.mjs +1693 -0
- package/src/core/pipeline-runtime.mjs +22 -1693
- package/src/core/scouts/engines/codex-app-subagent-engine.mjs +66 -5
- package/src/core/scouts/engines/codex-exec-parallel-engine.mjs +18 -4
- package/src/core/scouts/engines/scout-engine-base.mjs +5 -1
- package/src/core/scouts/engines/scout-engine-detect.mjs +7 -3
- package/src/core/scouts/engines/tmux-lane-cleanup.mjs +16 -0
- package/src/core/scouts/engines/tmux-lane-engine.mjs +72 -5
- package/src/core/scouts/engines/tmux-lane-watcher.mjs +26 -0
- package/src/core/scouts/scout-consensus.mjs +31 -0
- package/src/core/scouts/scout-output-fixtures.mjs +27 -0
- package/src/core/scouts/scout-output-normalizer.mjs +4 -0
- package/src/core/scouts/scout-output-parser.mjs +266 -0
- package/src/core/scouts/scout-output-validator.mjs +3 -0
- package/src/core/scouts/scout-readonly-guard.mjs +23 -2
- package/src/core/scouts/scout-runner.mjs +69 -11
- 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.
|
|
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
|

|
|
8
8
|
|
|
9
|
-
## 0.9.
|
|
9
|
+
## 0.9.19 Current Release
|
|
10
10
|
|
|
11
|
-
0.9.
|
|
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
|
-
-
|
|
16
|
-
- `
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
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
|
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
|
191
|
-
claim_allowed:
|
|
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('
|
|
57
|
-
'route-answer': fixture('
|
|
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 (!
|
|
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
|
|
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.
|
|
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
|
|