@harmonyos-arkts/d2h 0.1.5 → 0.1.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.
- package/README.md +19 -18
- package/agents/android-to-hmos-00-orchestrator.md +1 -1
- package/agents/d2h.md +101 -285
- package/dist/bin/install-opencode.js +9 -4
- package/dist/src/install-opencode.js +20 -1
- package/dist/src/install-vscode.js +6 -3
- package/dist/src/metrics-plugin.js +20 -0
- package/dist/src/toolchain.js +16 -12
- package/package.json +1 -1
- package/scripts/check-environment.mjs +1 -2
- package/skills/d2h-hypium-forge/SKILL.md +59 -2
- package/skills/d2h-hypium-forge/scripts/_common_template.py +85 -40
- package/skills/d2h-hypium-forge/scripts/analyze_results.py +11 -2
- package/skills/d2h-hypium-forge/scripts/probe.py +197 -0
- package/skills/d2h-hypium-forge/scripts/run_direct.py +464 -33
- package/skills/d2h-page-develop/SKILL.md +112 -0
- package/skills/d2h-page-develop/agents/openai.yaml +7 -0
- package/skills/d2h-page-spec-generate/SKILL.md +206 -0
- package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -0
- package/skills/managing-d2h-toolchain/SKILL.md +14 -13
- package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -0
- package/skills/appgraph-rule-audit/SKILL.md +0 -77
- package/skills/appgraph-rule-audit/references/audit-contract.md +0 -47
- package/skills/appgraph-rule-audit/references/recommendation-schema.md +0 -41
- package/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json +0 -125
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const skillDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
|
|
9
|
+
export function loadManifest(file = path.join(skillDir, 'toolchain.json')) {
|
|
10
|
+
const manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
11
|
+
if (manifest?.schemaVersion !== 1 || !manifest.tools || Array.isArray(manifest.tools) ||
|
|
12
|
+
!Object.keys(manifest.tools).length) throw new Error('invalid toolchain manifest');
|
|
13
|
+
for (const [name, tool] of Object.entries(manifest.tools)) {
|
|
14
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name) || tool?.package !== `@harmonyos-arkts/${name}` ||
|
|
15
|
+
!/^\d+\.\d+\.\d+$/.test(tool.version) || !tool.capabilities ||
|
|
16
|
+
!Object.keys(tool.capabilities).length || Object.values(tool.capabilities).some(args =>
|
|
17
|
+
!Array.isArray(args) || !args.length || args.some(arg => typeof arg !== 'string' || !arg))) {
|
|
18
|
+
throw new Error(`invalid toolchain entry: ${name}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return manifest;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function run(command, args) {
|
|
25
|
+
let executable = command;
|
|
26
|
+
let parameters = args;
|
|
27
|
+
if (process.platform === 'win32') {
|
|
28
|
+
const quote = value => `'${value.replaceAll("'", "''")}'`;
|
|
29
|
+
const binary = /^(npm|appgraph|droid2hmos)$/.test(command) ? `${command}.cmd` : command;
|
|
30
|
+
const script = `& ${[binary, ...args].map(quote).join(' ')}; exit $LASTEXITCODE`;
|
|
31
|
+
executable = 'powershell.exe';
|
|
32
|
+
parameters = ['-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')];
|
|
33
|
+
}
|
|
34
|
+
const result = spawnSync(executable, parameters, { encoding: 'utf8', windowsHide: true, timeout: 300000 });
|
|
35
|
+
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '', error: result.error };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function inspect(name, tool, runner = run) {
|
|
39
|
+
const result = runner(name, ['--version']);
|
|
40
|
+
const installedVersion = result.status === 0 ? /\b\d+\.\d+\.\d+\b/.exec(`${result.stdout}\n${result.stderr}`)?.[0] ?? null : null;
|
|
41
|
+
const capabilities = Object.fromEntries(Object.entries(tool.capabilities).map(([capability, args]) => {
|
|
42
|
+
const probe = installedVersion ? runner(name, args) : null;
|
|
43
|
+
const command = capability === 'analyze-android' ? 'analyze' : capability === 'build-android' ? 'build' : capability;
|
|
44
|
+
return [capability, probe?.status === 0 && `${probe.stdout}\n${probe.stderr}`.includes(command)];
|
|
45
|
+
}));
|
|
46
|
+
return { name, package: tool.package, expectedVersion: tool.version, installedVersion,
|
|
47
|
+
status: installedVersion === tool.version && Object.values(capabilities).every(Boolean) ? 'passed' : 'failed', capabilities };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function manage({ action = 'check', manifestFile, force = false, runner = run, log = console.log } = {}) {
|
|
51
|
+
if (!['check', 'install'].includes(action)) throw new Error(`unsupported action: ${action}`);
|
|
52
|
+
const manifest = loadManifest(manifestFile);
|
|
53
|
+
const results = Object.entries(manifest.tools).map(([name, tool]) => inspect(name, tool, runner));
|
|
54
|
+
for (const item of results) log(`${item.status}: ${item.package} expected ${item.expectedVersion}, installed ${item.installedVersion ?? 'missing'}; capabilities ${JSON.stringify(item.capabilities)}`);
|
|
55
|
+
if (action === 'check') return results.every(item => item.status === 'passed');
|
|
56
|
+
const targets = force ? results : results.filter(item => item.status !== 'passed');
|
|
57
|
+
if (!targets.length) return true;
|
|
58
|
+
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
59
|
+
const root = runner(npm, ['root', '--global']);
|
|
60
|
+
if (root.status !== 0 || !root.stdout.trim()) throw new Error(`cannot inspect global npm installation: ${root.stderr || root.error?.message || 'empty root'}`);
|
|
61
|
+
// Check every target before making changes, so a protected npm link cannot cause a partial installation.
|
|
62
|
+
for (const item of targets) {
|
|
63
|
+
const target = path.join(root.stdout.trim(), ...item.package.split('/'));
|
|
64
|
+
if (fs.existsSync(target) && fs.lstatSync(target).isSymbolicLink() && !force) {
|
|
65
|
+
throw new Error(`${item.package} is an npm link at ${target}; rerun with --force to replace it`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const item of targets) {
|
|
69
|
+
const coordinate = `${item.package}@${item.expectedVersion}`;
|
|
70
|
+
const target = path.join(root.stdout.trim(), ...item.package.split('/'));
|
|
71
|
+
const result = runner(npm, ['install', '--global', coordinate]);
|
|
72
|
+
if (result.status !== 0) throw new Error(`failed to install ${coordinate}: ${result.stderr || result.error?.message}`);
|
|
73
|
+
if (fs.existsSync(target) && fs.lstatSync(target).isSymbolicLink()) {
|
|
74
|
+
throw new Error(`${coordinate} installation completed but npm link remains at ${target}`);
|
|
75
|
+
}
|
|
76
|
+
const verified = inspect(item.name, manifest.tools[item.name], runner);
|
|
77
|
+
if (verified.status !== 'passed') throw new Error(`${coordinate} installed but CLI version or capabilities failed verification`);
|
|
78
|
+
log(`installed and verified ${coordinate}`);
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
84
|
+
try {
|
|
85
|
+
const [action = 'check', ...args] = process.argv.slice(2);
|
|
86
|
+
if (action === '--help' || action === '-h') {
|
|
87
|
+
console.log('Usage: node manage-toolchain.mjs check|install [--force]\nChecks exact AppGraph/droid2hmos versions and capabilities; install only changes missing or incompatible packages.');
|
|
88
|
+
} else {
|
|
89
|
+
if (args.some(arg => arg !== '--force') || args.filter(arg => arg === '--force').length > 1 || (action === 'check' && args.length)) {
|
|
90
|
+
throw new Error('usage: node manage-toolchain.mjs check|install [--force]');
|
|
91
|
+
}
|
|
92
|
+
if (!manage({ action, force: args.includes('--force') })) process.exitCode = 1;
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(`manage-toolchain: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: appgraph-rule-audit
|
|
3
|
-
description: Review fresh AppGraph and SPEC results after Android analysis, identify evidence-backed opportunities to improve page, ownership, and navigation rules, and write a local rule-opportunity report. Use after `droid2hmos analyze android` and before initializing the migration report; do not use it to edit analyzer output or implement rules.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Audit AppGraph rule opportunities
|
|
7
|
-
|
|
8
|
-
Review the latest deterministic Android analysis and produce maintainable rule-improvement candidates. This is a read-only diagnostic step. Do not edit AppGraph, SPEC facts, Android source, rule packs, or analyzers.
|
|
9
|
-
|
|
10
|
-
All `.migration/...` paths below live in the sibling migration workspace `<android-project>-migration/.migration/`. Never fall back to the legacy `<android-project>/.migration/`; if the sibling workspace or required artifacts are absent, return a structured unavailable/stale result.
|
|
11
|
-
|
|
12
|
-
## Preconditions
|
|
13
|
-
|
|
14
|
-
1. The caller must supply artifacts from a successful `droid2hmos analyze android <android-project>` run; this Skill does not run analysis itself.
|
|
15
|
-
2. Locate `.migration/spec/index.json`, `.migration/spec/facts/`, and `.migration/appgraph/app-graph.json`.
|
|
16
|
-
3. Check that the SPEC `generation.sourceRevision`, when present, matches the Android Git HEAD. Treat a mismatch or missing required artifact as stale analysis: write no recommendations and return the structured result below. Do not run analysis or ask the user whether to run it.
|
|
17
|
-
4. Keep all source and generated data local. Network access is unnecessary.
|
|
18
|
-
|
|
19
|
-
## Review workflow
|
|
20
|
-
|
|
21
|
-
1. Read only the indexes and summaries first. Record page counts by type, navigation edges, ownership/host edges, unresolved counts, reachability gaps, coverage warnings, rule-pack versions, and rule contribution/drop/conflict counts.
|
|
22
|
-
2. Group gaps by stable evidence shape rather than business page name:
|
|
23
|
-
- unresolved reason;
|
|
24
|
-
- framework/package/base type/annotation;
|
|
25
|
-
- receiver and method call shape;
|
|
26
|
-
- route declaration or factory pattern;
|
|
27
|
-
- missing host, target, caller, projection, or uniqueness evidence.
|
|
28
|
-
3. Prioritize repeated or high-impact clusters. Inspect at most five representative samples per cluster initially. Read additional source only when it changes the diagnosis.
|
|
29
|
-
4. Classify each candidate using [references/audit-contract.md](references/audit-contract.md). Determine whether evidence is missing in Analyzer, rejected by Judge, lost during Lift, omitted from SPEC, missing a host, or indicates a false positive.
|
|
30
|
-
5. Establish a positive example and a similar negative or ambiguous example before proposing a generic or framework rule. If the target is dynamic, reflective, or non-unique, record it as an accepted limitation instead of proposing an unsafe rule.
|
|
31
|
-
6. Compare with a previous report for the same source project when available. Treat newly added pages/edges, disappearing pages/edges, changed direction, and changed ownership as accuracy signals; raw count growth is not automatically an improvement.
|
|
32
|
-
7. Rank opportunities by impact, recurrence, evidence strength, generality, false-positive risk, and implementation cost. Keep at most 20 active opportunities.
|
|
33
|
-
8. Write the two outputs defined below. Follow [references/recommendation-schema.md](references/recommendation-schema.md) exactly.
|
|
34
|
-
|
|
35
|
-
## Outputs
|
|
36
|
-
|
|
37
|
-
When analysis is missing or stale, return without creating or replacing opportunity reports:
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
{
|
|
41
|
-
"status": "stale",
|
|
42
|
-
"workspace": "<android-project>-migration/.migration/",
|
|
43
|
-
"staleReasons": [],
|
|
44
|
-
"requiredAction": "reanalyze-android",
|
|
45
|
-
"expectedArtifacts": [
|
|
46
|
-
".migration/spec/index.json",
|
|
47
|
-
".migration/spec/facts/",
|
|
48
|
-
".migration/appgraph/app-graph.json"
|
|
49
|
-
]
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
The caller consumes `requiredAction` and decides the workflow transition. This Skill does not invoke `droid2hmos analyze android`, pause for a user choice, or continue against legacy/stale artifacts.
|
|
54
|
-
|
|
55
|
-
When inputs are fresh, create or replace:
|
|
56
|
-
|
|
57
|
-
```text
|
|
58
|
-
.migration/rule-audit/rule-opportunities.json
|
|
59
|
-
.migration/rule-audit/rule-opportunities.md
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The JSON must conform to `schemas/rule-opportunities.schema.json` in this Skill. The Markdown is the human review view of the same findings; it must not add claims absent from JSON.
|
|
63
|
-
|
|
64
|
-
Each opportunity must include evidence refs with Android source file and line, the affected AppGraph/SPEC entities, current and expected behavior, proposed change layer, scope, confidence, generality, risk, and a concrete test plan. Separate observations from inferred root causes and label uncertain causes as hypotheses.
|
|
65
|
-
|
|
66
|
-
When no evidence-backed rule improvement exists, write valid outputs with an empty `opportunities` array and explain the reviewed limitations. Do not invent work to avoid an empty report.
|
|
67
|
-
|
|
68
|
-
## Boundaries
|
|
69
|
-
|
|
70
|
-
- Do not modify immutable `.migration/spec/facts/` or `app-graph.json`.
|
|
71
|
-
- Do not write a project screen name into a generic rule proposal.
|
|
72
|
-
- Do not call a suffix match, route-string similarity, or nearest-name guess sufficient evidence.
|
|
73
|
-
- Do not turn host relationships into navigation edges.
|
|
74
|
-
- Do not mark multiple targets as resolved.
|
|
75
|
-
- Do not implement recommendations. A maintainer may later pass an accepted opportunity to the separate `appgraph-navigation-rules` Skill.
|
|
76
|
-
- With fresh inputs, an audit execution failure is advisory: record the limitation and return it to the caller. Missing or stale analysis is not an audit failure; return `requiredAction: reanalyze-android` as defined above.
|
|
77
|
-
- Do not advance an outer state, create a checkpoint, update the migration report, or invoke completion. Return findings or the stale result to the caller.
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Rule audit contract
|
|
2
|
-
|
|
3
|
-
Use this reference to classify a finding and decide whether it is actionable.
|
|
4
|
-
|
|
5
|
-
## Layers
|
|
6
|
-
|
|
7
|
-
### analyzer-gap
|
|
8
|
-
|
|
9
|
-
The Android source contains stable syntax or type evidence, but `ruleEngine.contributions` has no corresponding facts. A proposal must name the API identity and facts an Analyzer should emit. JSON5 Judge conditions cannot repair this gap.
|
|
10
|
-
|
|
11
|
-
### judge-gap
|
|
12
|
-
|
|
13
|
-
Required facts exist, but no rule confirms them or the contribution is dropped. Cite the existing fact paths, matching/drop result, and the smallest condition change. Preserve ambiguity.
|
|
14
|
-
|
|
15
|
-
### lift-gap
|
|
16
|
-
|
|
17
|
-
The contribution is confirmed, but the expected Screen/host/navigation node or edge is absent from AppGraph. Cite the matched rule and expected graph projection.
|
|
18
|
-
|
|
19
|
-
### spec-gap
|
|
20
|
-
|
|
21
|
-
The AppGraph node or edge exists with valid provenance, but SPEC facts omit or misclassify it. Cite both the AppGraph entity and missing SPEC representation.
|
|
22
|
-
|
|
23
|
-
### host-gap
|
|
24
|
-
|
|
25
|
-
A page is recognized but lacks a deterministic owner or upstream host. Propose a rule only when the host chain follows a stable framework API, factory, entry point, or unique call relationship. Never infer a host from proximity or a single Activity fallback.
|
|
26
|
-
|
|
27
|
-
### false-positive
|
|
28
|
-
|
|
29
|
-
A recognized page, host, or transition is a component, preview, test fixture, factory, helper, or unrelated call. Cite the matched rule and a structural discriminator that excludes the bad result without naming the product entity.
|
|
30
|
-
|
|
31
|
-
### performance
|
|
32
|
-
|
|
33
|
-
A rule or analyzer has observed pathological cost. Cite timings, affected stage, input shape, and a bounded alternative. Do not infer performance problems from project size alone.
|
|
34
|
-
|
|
35
|
-
## Scope
|
|
36
|
-
|
|
37
|
-
- `builtin-generic`: supported Android or Jetpack API with evidence across unrelated projects or authoritative framework structure.
|
|
38
|
-
- `framework-pack`: stable third-party or private framework identity such as package, base type, annotation, receiver type, or route registry.
|
|
39
|
-
- `project-pack`: valid behavior tied to one project's local abstraction without enough evidence for broader scope.
|
|
40
|
-
|
|
41
|
-
## Evidence minimum
|
|
42
|
-
|
|
43
|
-
Every opportunity needs one positive source example and its current generated result. A `builtin-generic` or `framework-pack` opportunity also needs a negative, boundary, or ambiguous example demonstrating how false matches will be prevented. Evidence includes project-relative file, line when available, symbol/call shape, related entity refs, and related rule IDs.
|
|
44
|
-
|
|
45
|
-
## Accepted limitations
|
|
46
|
-
|
|
47
|
-
Use an accepted limitation for reflection, runtime-generated destinations, remote configuration, unresolved dependency types, multiple valid targets, or missing source. Explain what evidence would be required to resolve it. Do not propose a low-confidence guessing rule.
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Rule opportunity output
|
|
2
|
-
|
|
3
|
-
Write JSON matching `schemas/rule-opportunities.schema.json` in this Skill and a concise Chinese Markdown rendering.
|
|
4
|
-
|
|
5
|
-
## Top-level fields
|
|
6
|
-
|
|
7
|
-
- `schemaVersion`: `1.0.0`.
|
|
8
|
-
- `skillVersion`: `1.0.0`.
|
|
9
|
-
- `source`: Android project identity, source revision, `factsSha256`, and observed AppGraph/rule-pack versions.
|
|
10
|
-
- `summary`: reviewed counts and a short conclusion.
|
|
11
|
-
- `opportunities`: at most 20 ranked candidates.
|
|
12
|
-
- `acceptedLimitations`: evidence-backed gaps that should remain unresolved.
|
|
13
|
-
- `auditWarnings`: stale, incomplete, or unavailable inputs that limit confidence.
|
|
14
|
-
|
|
15
|
-
## Opportunity fields
|
|
16
|
-
|
|
17
|
-
- `id`: stable lowercase ID derived from category, framework identity, and evidence shape; never use list position.
|
|
18
|
-
- `priority`: `P0`, `P1`, or `P2`. Use P0 only for systemic false results or a blocker affecting a large part of the page/navigation graph.
|
|
19
|
-
- `category`: one audit layer from the contract.
|
|
20
|
-
- `scope`: `builtin-generic`, `framework-pack`, or `project-pack`.
|
|
21
|
-
- `title`: concise problem statement.
|
|
22
|
-
- `frameworkIdentity`: stable package/type/annotation/receiver/call identity.
|
|
23
|
-
- `observation`: directly observed current result.
|
|
24
|
-
- `rootCause`: diagnosis plus `certainty` of `confirmed` or `hypothesis`.
|
|
25
|
-
- `expectedBehavior`: required page, host, edge, projection, exclusion, or performance behavior.
|
|
26
|
-
- `affectedEntities`: page/edge/contribution refs.
|
|
27
|
-
- `evidence`: source locations, generated refs, rule IDs, and the evidence role (`positive`, `negative`, `boundary`, `ambiguous`).
|
|
28
|
-
- `proposal`: target layer, proposed rule shape, and files or rule IDs likely to change; no executable patch.
|
|
29
|
-
- `confidence`, `generality`, `risk`: `high`, `medium`, or `low`, each with a reason.
|
|
30
|
-
- `testPlan`: positive, negative, boundary, ambiguity, Lift/SPEC, and project baseline checks as applicable.
|
|
31
|
-
- `expectedMetricDelta`: directional expectation for pages, navigation, hosts, unresolved, and false positives; use `unknown` when unsupported.
|
|
32
|
-
- `status`: always `proposed` in this Skill.
|
|
33
|
-
|
|
34
|
-
## Markdown order
|
|
35
|
-
|
|
36
|
-
1. Input freshness and coverage summary.
|
|
37
|
-
2. Ranked opportunities with evidence and tests.
|
|
38
|
-
3. Accepted limitations.
|
|
39
|
-
4. Audit warnings.
|
|
40
|
-
|
|
41
|
-
Do not reproduce the full page inventory or migration report.
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://harmonyos-ai.dev/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json",
|
|
4
|
-
"title": "AppGraph rule improvement opportunities",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"required": ["schemaVersion", "skillVersion", "source", "summary", "opportunities", "acceptedLimitations", "auditWarnings"],
|
|
7
|
-
"properties": {
|
|
8
|
-
"schemaVersion": { "const": "1.0.0" },
|
|
9
|
-
"skillVersion": { "const": "1.0.0" },
|
|
10
|
-
"source": {
|
|
11
|
-
"type": "object",
|
|
12
|
-
"required": ["project", "sourceRevision", "factsSha256", "appGraphVersion", "rulePacks"],
|
|
13
|
-
"properties": {
|
|
14
|
-
"project": { "type": "string", "minLength": 1 },
|
|
15
|
-
"sourceRevision": { "type": ["string", "null"] },
|
|
16
|
-
"factsSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
17
|
-
"appGraphVersion": { "type": ["string", "null"] },
|
|
18
|
-
"rulePacks": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
19
|
-
},
|
|
20
|
-
"additionalProperties": false
|
|
21
|
-
},
|
|
22
|
-
"summary": {
|
|
23
|
-
"type": "object",
|
|
24
|
-
"required": ["conclusion", "pages", "navigation", "hosts", "unresolved", "coverageWarnings"],
|
|
25
|
-
"properties": {
|
|
26
|
-
"conclusion": { "type": "string" },
|
|
27
|
-
"pages": { "type": "integer", "minimum": 0 },
|
|
28
|
-
"navigation": { "type": "integer", "minimum": 0 },
|
|
29
|
-
"hosts": { "type": "integer", "minimum": 0 },
|
|
30
|
-
"unresolved": { "type": "integer", "minimum": 0 },
|
|
31
|
-
"coverageWarnings": { "type": "integer", "minimum": 0 }
|
|
32
|
-
},
|
|
33
|
-
"additionalProperties": false
|
|
34
|
-
},
|
|
35
|
-
"opportunities": { "type": "array", "maxItems": 20, "items": { "$ref": "#/$defs/opportunity" } },
|
|
36
|
-
"acceptedLimitations": { "type": "array", "items": { "$ref": "#/$defs/limitation" } },
|
|
37
|
-
"auditWarnings": { "type": "array", "items": { "type": "string", "minLength": 1 } }
|
|
38
|
-
},
|
|
39
|
-
"$defs": {
|
|
40
|
-
"level": { "enum": ["high", "medium", "low"] },
|
|
41
|
-
"evidence": {
|
|
42
|
-
"type": "object",
|
|
43
|
-
"required": ["role", "file", "line", "symbol", "entityRefs", "ruleIds", "observation"],
|
|
44
|
-
"properties": {
|
|
45
|
-
"role": { "enum": ["positive", "negative", "boundary", "ambiguous"] },
|
|
46
|
-
"file": { "type": "string", "minLength": 1 },
|
|
47
|
-
"line": { "type": ["integer", "null"], "minimum": 1 },
|
|
48
|
-
"symbol": { "type": ["string", "null"] },
|
|
49
|
-
"entityRefs": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
50
|
-
"ruleIds": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
51
|
-
"observation": { "type": "string", "minLength": 1 }
|
|
52
|
-
},
|
|
53
|
-
"additionalProperties": false
|
|
54
|
-
},
|
|
55
|
-
"ratedReason": {
|
|
56
|
-
"type": "object",
|
|
57
|
-
"required": ["level", "reason"],
|
|
58
|
-
"properties": { "level": { "$ref": "#/$defs/level" }, "reason": { "type": "string", "minLength": 1 } },
|
|
59
|
-
"additionalProperties": false
|
|
60
|
-
},
|
|
61
|
-
"metricDelta": {
|
|
62
|
-
"type": "object",
|
|
63
|
-
"required": ["pages", "navigation", "hosts", "unresolved", "falsePositives"],
|
|
64
|
-
"properties": {
|
|
65
|
-
"pages": { "enum": ["increase", "decrease", "unchanged", "unknown"] },
|
|
66
|
-
"navigation": { "enum": ["increase", "decrease", "unchanged", "unknown"] },
|
|
67
|
-
"hosts": { "enum": ["increase", "decrease", "unchanged", "unknown"] },
|
|
68
|
-
"unresolved": { "enum": ["increase", "decrease", "unchanged", "unknown"] },
|
|
69
|
-
"falsePositives": { "enum": ["increase", "decrease", "unchanged", "unknown"] }
|
|
70
|
-
},
|
|
71
|
-
"additionalProperties": false
|
|
72
|
-
},
|
|
73
|
-
"opportunity": {
|
|
74
|
-
"type": "object",
|
|
75
|
-
"required": ["id", "priority", "category", "scope", "title", "frameworkIdentity", "observation", "rootCause", "expectedBehavior", "affectedEntities", "evidence", "proposal", "confidence", "generality", "risk", "testPlan", "expectedMetricDelta", "status"],
|
|
76
|
-
"properties": {
|
|
77
|
-
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]+$" },
|
|
78
|
-
"priority": { "enum": ["P0", "P1", "P2"] },
|
|
79
|
-
"category": { "enum": ["analyzer-gap", "judge-gap", "lift-gap", "spec-gap", "host-gap", "false-positive", "performance"] },
|
|
80
|
-
"scope": { "enum": ["builtin-generic", "framework-pack", "project-pack"] },
|
|
81
|
-
"title": { "type": "string", "minLength": 1 },
|
|
82
|
-
"frameworkIdentity": { "type": "string", "minLength": 1 },
|
|
83
|
-
"observation": { "type": "string", "minLength": 1 },
|
|
84
|
-
"rootCause": {
|
|
85
|
-
"type": "object",
|
|
86
|
-
"required": ["certainty", "description"],
|
|
87
|
-
"properties": { "certainty": { "enum": ["confirmed", "hypothesis"] }, "description": { "type": "string", "minLength": 1 } },
|
|
88
|
-
"additionalProperties": false
|
|
89
|
-
},
|
|
90
|
-
"expectedBehavior": { "type": "string", "minLength": 1 },
|
|
91
|
-
"affectedEntities": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
|
|
92
|
-
"evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/evidence" } },
|
|
93
|
-
"proposal": {
|
|
94
|
-
"type": "object",
|
|
95
|
-
"required": ["layer", "ruleShape", "likelyFilesOrRules"],
|
|
96
|
-
"properties": {
|
|
97
|
-
"layer": { "enum": ["Analyzer", "Judge", "Lift", "SPEC", "Host", "Performance"] },
|
|
98
|
-
"ruleShape": { "type": "string", "minLength": 1 },
|
|
99
|
-
"likelyFilesOrRules": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
|
|
100
|
-
},
|
|
101
|
-
"additionalProperties": false
|
|
102
|
-
},
|
|
103
|
-
"confidence": { "$ref": "#/$defs/ratedReason" },
|
|
104
|
-
"generality": { "$ref": "#/$defs/ratedReason" },
|
|
105
|
-
"risk": { "$ref": "#/$defs/ratedReason" },
|
|
106
|
-
"testPlan": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
|
|
107
|
-
"expectedMetricDelta": { "$ref": "#/$defs/metricDelta" },
|
|
108
|
-
"status": { "const": "proposed" }
|
|
109
|
-
},
|
|
110
|
-
"additionalProperties": false
|
|
111
|
-
},
|
|
112
|
-
"limitation": {
|
|
113
|
-
"type": "object",
|
|
114
|
-
"required": ["id", "reason", "evidence", "requiredEvidence"],
|
|
115
|
-
"properties": {
|
|
116
|
-
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]+$" },
|
|
117
|
-
"reason": { "type": "string", "minLength": 1 },
|
|
118
|
-
"evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/evidence" } },
|
|
119
|
-
"requiredEvidence": { "type": "string", "minLength": 1 }
|
|
120
|
-
},
|
|
121
|
-
"additionalProperties": false
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
"additionalProperties": false
|
|
125
|
-
}
|