@devtrack-solution/codesdd 1.2.3 → 1.2.4
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/.sdd/skills/curated/devtrack-api/SKILL.md +98 -12
- package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +5 -3
- package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +12 -0
- package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +61 -5
- package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +15 -3
- package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +1951 -0
- package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +16 -14
- package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +40 -0
- package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +19 -2
- package/.sdd/skills/curated/devtrack-api/references/generated-artifact-invalidation.md +97 -0
- package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +30 -1
- package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +42 -0
- package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +22 -1
- package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +9 -7
- package/README.md +280 -29
- package/dist/applications/sdd/index.d.ts +16 -0
- package/dist/applications/sdd/index.js +16 -0
- package/dist/cli/program.js +180 -11
- package/dist/commands/config.js +197 -10
- package/dist/commands/sdd/execution.js +408 -16
- package/dist/commands/sdd/plugin.js +5 -0
- package/dist/commands/sdd/shared.d.ts +1 -0
- package/dist/commands/sdd/shared.js +10 -0
- package/dist/commands/sdd.js +157 -7
- package/dist/core/cli/command-matrix.d.ts +18 -0
- package/dist/core/cli/command-matrix.js +157 -0
- package/dist/core/cli-command-quality.js +11 -0
- package/dist/core/completions/command-registry.js +45 -0
- package/dist/core/config-schema.d.ts +31 -1
- package/dist/core/config-schema.js +79 -5
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +11 -0
- package/dist/core/global-config.d.ts +29 -0
- package/dist/core/init.d.ts +2 -2
- package/dist/core/init.js +13 -14
- package/dist/core/sdd/agent-binding.d.ts +19 -19
- package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
- package/dist/core/sdd/agent-runtime-contract.js +200 -0
- package/dist/core/sdd/allocator-recovery.d.ts +14 -0
- package/dist/core/sdd/allocator-recovery.js +30 -0
- package/dist/core/sdd/allocator-security.d.ts +18 -0
- package/dist/core/sdd/allocator-security.js +36 -0
- package/dist/core/sdd/api-foundation-baseline.d.ts +111 -0
- package/dist/core/sdd/api-foundation-baseline.js +151 -0
- package/dist/core/sdd/api-foundation-parity.d.ts +114 -0
- package/dist/core/sdd/api-foundation-parity.js +131 -0
- package/dist/core/sdd/api-profile-catalog.d.ts +36 -0
- package/dist/core/sdd/api-profile-catalog.js +132 -0
- package/dist/core/sdd/api-profile-dry-run-projection.d.ts +93 -0
- package/dist/core/sdd/api-profile-dry-run-projection.js +370 -0
- package/dist/core/sdd/api-profile-recipes.d.ts +82 -0
- package/dist/core/sdd/api-profile-recipes.js +484 -0
- package/dist/core/sdd/artifact-id-allocator.d.ts +368 -0
- package/dist/core/sdd/artifact-id-allocator.js +510 -0
- package/dist/core/sdd/check.d.ts +52 -1
- package/dist/core/sdd/check.js +326 -11
- package/dist/core/sdd/coordination/coordination-adapters.d.ts +15 -8
- package/dist/core/sdd/coordination/coordination-adapters.js +43 -15
- package/dist/core/sdd/coordination/index.d.ts +1 -0
- package/dist/core/sdd/coordination/index.js +1 -0
- package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
- package/dist/core/sdd/coordination/redis-runtime.js +698 -0
- package/dist/core/sdd/deepagent-contracts.d.ts +99 -5
- package/dist/core/sdd/deepagent-contracts.js +62 -0
- package/dist/core/sdd/deepagents/reversa-subagents.d.ts +3 -3
- package/dist/core/sdd/default-bootstrap-files.d.ts +2 -2
- package/dist/core/sdd/default-bootstrap-files.js +14 -10
- package/dist/core/sdd/default-skills.js +115 -9
- package/dist/core/sdd/devtrack-api-appliance.d.ts +42 -1
- package/dist/core/sdd/devtrack-api-appliance.js +159 -32
- package/dist/core/sdd/devtrack-api-architecture.d.ts +16 -0
- package/dist/core/sdd/devtrack-api-architecture.js +86 -0
- package/dist/core/sdd/docs-sync.js +24 -18
- package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
- package/dist/core/sdd/domain/capability-diff.js +200 -0
- package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
- package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
- package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
- package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
- package/dist/core/sdd/enterprise-mutating-command-gate.d.ts +27 -0
- package/dist/core/sdd/enterprise-mutating-command-gate.js +104 -0
- package/dist/core/sdd/enterprise-provenance-gates.d.ts +20 -0
- package/dist/core/sdd/enterprise-provenance-gates.js +63 -0
- package/dist/core/sdd/enterprise-provisioning-policy.d.ts +26 -0
- package/dist/core/sdd/enterprise-provisioning-policy.js +104 -0
- package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
- package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
- package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
- package/dist/core/sdd/foundation-layer-manifest.js +117 -0
- package/dist/core/sdd/governance-schemas.d.ts +2 -2
- package/dist/core/sdd/governance-schemas.js +11 -2
- package/dist/core/sdd/intent-guard.d.ts +22 -0
- package/dist/core/sdd/intent-guard.js +67 -0
- package/dist/core/sdd/json-schema.js +13 -1
- package/dist/core/sdd/legacy-operations.js +169 -5
- package/dist/core/sdd/migrate-workspace.js +39 -0
- package/dist/core/sdd/package-security-gates.d.ts +21 -0
- package/dist/core/sdd/package-security-gates.js +121 -0
- package/dist/core/sdd/package-structure-gate.d.ts +85 -3
- package/dist/core/sdd/package-structure-gate.js +384 -11
- package/dist/core/sdd/parallel-feat-automation.d.ts +185 -7
- package/dist/core/sdd/parallel-feat-automation.js +212 -0
- package/dist/core/sdd/plugin-broker.d.ts +223 -4
- package/dist/core/sdd/plugin-broker.js +10 -0
- package/dist/core/sdd/plugin-cli.d.ts +30 -0
- package/dist/core/sdd/plugin-cli.js +70 -3
- package/dist/core/sdd/plugin-evidence.d.ts +73 -0
- package/dist/core/sdd/plugin-manifest.d.ts +69 -1
- package/dist/core/sdd/plugin-manifest.js +10 -0
- package/dist/core/sdd/plugin-policy-pack.d.ts +1 -1
- package/dist/core/sdd/plugin-policy.js +6 -1
- package/dist/core/sdd/plugin-registry.d.ts +138 -2
- package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
- package/dist/core/sdd/plugin-sdk-contract.js +268 -0
- package/dist/core/sdd/plugin-skill-binding.d.ts +1 -1
- package/dist/core/sdd/quality-validation.d.ts +89 -16
- package/dist/core/sdd/release-readiness.d.ts +68 -0
- package/dist/core/sdd/release-readiness.js +767 -0
- package/dist/core/sdd/reversa-architecture-extractor.d.ts +13 -0
- package/dist/core/sdd/reversa-architecture-extractor.js +89 -0
- package/dist/core/sdd/reversa-artifact-writer.d.ts +18 -0
- package/dist/core/sdd/reversa-artifact-writer.js +40 -0
- package/dist/core/sdd/reversa-command-policy.d.ts +136 -0
- package/dist/core/sdd/reversa-command-policy.js +361 -0
- package/dist/core/sdd/reversa-data-extractor.d.ts +11 -0
- package/dist/core/sdd/reversa-data-extractor.js +73 -0
- package/dist/core/sdd/reversa-equivalence.d.ts +20 -0
- package/dist/core/sdd/reversa-equivalence.js +34 -0
- package/dist/core/sdd/reversa-evidence.d.ts +298 -0
- package/dist/core/sdd/reversa-evidence.js +118 -0
- package/dist/core/sdd/reversa-reconstruction.d.ts +29 -0
- package/dist/core/sdd/reversa-reconstruction.js +32 -0
- package/dist/core/sdd/reversa-rules-extractor.d.ts +12 -0
- package/dist/core/sdd/reversa-rules-extractor.js +86 -0
- package/dist/core/sdd/reversa-source-safety.d.ts +19 -0
- package/dist/core/sdd/reversa-source-safety.js +105 -0
- package/dist/core/sdd/reversa-surface-scout.d.ts +13 -0
- package/dist/core/sdd/reversa-surface-scout.js +85 -0
- package/dist/core/sdd/reversa-ux-mapper.d.ts +11 -0
- package/dist/core/sdd/reversa-ux-mapper.js +73 -0
- package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
- package/dist/core/sdd/runtime-boundary-contract.js +90 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
- package/dist/core/sdd/services/agent-run.service.d.ts +38 -6
- package/dist/core/sdd/services/agent-run.service.js +73 -1
- package/dist/core/sdd/services/archive-quality-coherence.service.d.ts +17 -0
- package/dist/core/sdd/services/archive-quality-coherence.service.js +141 -0
- package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
- package/dist/core/sdd/services/capability-diff.service.js +26 -0
- package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
- package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
- package/dist/core/sdd/services/context.service.d.ts +43 -340
- package/dist/core/sdd/services/context.service.js +323 -9
- package/dist/core/sdd/services/decide.service.js +1 -1
- package/dist/core/sdd/services/finalize.service.d.ts +27 -0
- package/dist/core/sdd/services/finalize.service.js +226 -18
- package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
- package/dist/core/sdd/services/historical-quality-regression.service.d.ts +35 -0
- package/dist/core/sdd/services/historical-quality-regression.service.js +228 -0
- package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
- package/dist/core/sdd/services/planning-execution-coherence.service.d.ts +45 -0
- package/dist/core/sdd/services/planning-execution-coherence.service.js +225 -0
- package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
- package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
- package/dist/core/sdd/state.d.ts +1 -0
- package/dist/core/sdd/state.js +266 -34
- package/dist/core/sdd/store/sdd-stores.js +2 -2
- package/dist/core/sdd/structural-health.d.ts +13 -13
- package/dist/core/sdd/types.d.ts +30 -15
- package/dist/core/sdd/types.js +4 -0
- package/dist/core/sdd/views.js +17 -0
- package/dist/core/sdd/workspace-schemas.d.ts +428 -7
- package/dist/core/sdd/workspace-schemas.js +223 -70
- package/dist/core/shared/skill-generation.d.ts +2 -0
- package/dist/core/shared/skill-generation.js +19 -2
- package/dist/core/shared/tool-detection.d.ts +19 -0
- package/dist/core/shared/tool-detection.js +89 -0
- package/dist/domains/sdd/index.d.ts +6 -0
- package/dist/domains/sdd/index.js +6 -0
- package/dist/infrastructures/sdd/index.d.ts +7 -0
- package/dist/infrastructures/sdd/index.js +6 -0
- package/dist/presentations/cli/sdd/index.d.ts +3 -0
- package/dist/presentations/cli/sdd/index.js +3 -0
- package/dist/shared/sdd/index.d.ts +3 -0
- package/dist/shared/sdd/index.js +2 -0
- package/package.json +14 -10
- package/schemas/sdd/2-plan.schema.json +207 -2
- package/schemas/sdd/5-quality.schema.json +324 -25
- package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
- package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
- package/schemas/sdd/codesdd-plugin.schema.json +171 -0
- package/schemas/sdd/deepagent-run-request.schema.json +316 -0
- package/schemas/sdd/parallel-feat-automation-plan.schema.json +89 -0
- package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
- package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
- package/schemas/sdd/plugin-artifact-manifest.schema.json +109 -0
- package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
- package/schemas/sdd/plugin-evidence-manifest.schema.json +109 -0
- package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
- package/schemas/sdd/plugin-package-governance.schema.json +74 -0
- package/schemas/sdd/plugin-registry.schema.json +171 -0
- package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +109 -0
- package/schemas/sdd/quality-evidence-bundle.schema.json +109 -0
- package/schemas/sdd/reversa-evidence-bundle.schema.json +466 -0
- package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
- package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
- package/schemas/sdd/workspace-catalog.schema.json +5298 -1409
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReversaEvidenceBundle } from './reversa-evidence.js';
|
|
2
|
+
export interface ReversaArchitectureSource {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BuildReversaArchitectureMapInput {
|
|
7
|
+
featureRef: string;
|
|
8
|
+
operationId: string;
|
|
9
|
+
generatedAt: string;
|
|
10
|
+
sources: ReversaArchitectureSource[];
|
|
11
|
+
}
|
|
12
|
+
export declare function buildReversaArchitectureMap(input: BuildReversaArchitectureMapInput): ReversaEvidenceBundle;
|
|
13
|
+
//# sourceMappingURL=reversa-architecture-extractor.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { attestReversaSource } from './reversa-source-safety.js';
|
|
2
|
+
export function buildReversaArchitectureMap(input) {
|
|
3
|
+
const accepted = input.sources
|
|
4
|
+
.map((source) => ({ source, attestation: attestReversaSource({ sourcePath: source.path, content: source.content }) }))
|
|
5
|
+
.filter((entry) => entry.attestation.status === 'accepted' && entry.attestation.attestation);
|
|
6
|
+
const blockedCount = input.sources.length - accepted.length;
|
|
7
|
+
const modules = accepted.flatMap(({ source, attestation }) => scanModules(attestation.normalized_path, source.content));
|
|
8
|
+
const dependencies = accepted.flatMap(({ source, attestation }) => scanDependencies(attestation.normalized_path, source.content));
|
|
9
|
+
const findings = [];
|
|
10
|
+
if (modules.length > 0) {
|
|
11
|
+
findings.push({
|
|
12
|
+
id: 'REV-FIND-ARCH-MODULES',
|
|
13
|
+
phase: 'architecture',
|
|
14
|
+
title: 'Architecture modules',
|
|
15
|
+
summary: `Detected ${modules.length} module or class boundaries.`,
|
|
16
|
+
confidence: 'medium',
|
|
17
|
+
source_refs: unique(modules.map((entry) => entry.source_ref)),
|
|
18
|
+
contradiction_refs: [],
|
|
19
|
+
promoted_refs: [],
|
|
20
|
+
metadata: { modules },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (dependencies.length > 0) {
|
|
24
|
+
findings.push({
|
|
25
|
+
id: 'REV-FIND-ARCH-DEPENDENCIES',
|
|
26
|
+
phase: 'architecture',
|
|
27
|
+
title: 'Dependency imports',
|
|
28
|
+
summary: `Detected ${dependencies.length} import or require dependencies.`,
|
|
29
|
+
confidence: 'medium',
|
|
30
|
+
source_refs: unique(dependencies.map((entry) => entry.source_ref)),
|
|
31
|
+
contradiction_refs: [],
|
|
32
|
+
promoted_refs: [],
|
|
33
|
+
metadata: { dependencies },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
schema_version: 1,
|
|
38
|
+
contract: 'reversa-evidence-bundle/v1',
|
|
39
|
+
operation_id: input.operationId,
|
|
40
|
+
generated_at: input.generatedAt,
|
|
41
|
+
feature_ref: input.featureRef,
|
|
42
|
+
mode: 'read-only',
|
|
43
|
+
source_attestations: accepted.map((entry) => entry.attestation.attestation),
|
|
44
|
+
findings,
|
|
45
|
+
artifacts: [
|
|
46
|
+
{
|
|
47
|
+
path: `.sdd/evidence/reversa/${input.featureRef}/architecture-map.yaml`,
|
|
48
|
+
artifact_type: 'architecture_map',
|
|
49
|
+
phase: 'architecture',
|
|
50
|
+
produced_by: 'codesdd reversa architecture extractor',
|
|
51
|
+
write_scope: 'read_only',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
validations: [
|
|
55
|
+
{
|
|
56
|
+
id: 'REV-VAL-ARCH-SAFETY',
|
|
57
|
+
phase: 'architecture',
|
|
58
|
+
command: 'buildReversaArchitectureMap',
|
|
59
|
+
status: blockedCount === 0 ? 'passed' : 'blocked',
|
|
60
|
+
issue_codes: blockedCount === 0 ? [] : ['UNSAFE_SOURCE_BLOCKED'],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
contradictions: [],
|
|
64
|
+
human_questions: [],
|
|
65
|
+
quality_refs: [`.sdd/active/${input.featureRef}/5-quality.yaml`],
|
|
66
|
+
residual_risks: blockedCount === 0 ? [] : [{
|
|
67
|
+
code: 'UNSAFE_SOURCE_BLOCKED',
|
|
68
|
+
severity: 'medium',
|
|
69
|
+
description: `${blockedCount} source(s) were blocked by Reversa intake safety.`,
|
|
70
|
+
mitigation: 'Provide safe project-relative sources before architecture extraction.',
|
|
71
|
+
}],
|
|
72
|
+
metadata: { module_count: modules.length, dependency_count: dependencies.length },
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function scanModules(sourceRef, content) {
|
|
76
|
+
return [...content.matchAll(/\b(?:class|interface|module|namespace)\s+([A-Za-z0-9_]+)/gu)].map((match) => ({
|
|
77
|
+
name: match[1] ?? 'unknown',
|
|
78
|
+
source_ref: sourceRef,
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
function scanDependencies(sourceRef, content) {
|
|
82
|
+
const imports = [...content.matchAll(/\bimport\b[^'"]*['"]([^'"]+)['"]/gu)].map((match) => match[1] ?? '');
|
|
83
|
+
const requires = [...content.matchAll(/\brequire\(\s*['"]([^'"]+)['"]\s*\)/gu)].map((match) => match[1] ?? '');
|
|
84
|
+
return [...imports, ...requires].filter(Boolean).map((target) => ({ target, source_ref: sourceRef }));
|
|
85
|
+
}
|
|
86
|
+
function unique(values) {
|
|
87
|
+
return [...new Set(values)];
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=reversa-architecture-extractor.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReversaEvidenceBundle } from './reversa-evidence.js';
|
|
2
|
+
export interface ReversaArtifactWritePlan {
|
|
3
|
+
schema_version: 1;
|
|
4
|
+
contract: 'reversa-artifact-write-plan/v1';
|
|
5
|
+
feature_ref: string;
|
|
6
|
+
status: 'ready' | 'needs_clarification';
|
|
7
|
+
draft_artifacts: Array<{
|
|
8
|
+
artifact_type: 'INS' | 'DEB' | 'EPIC' | 'FEAT' | 'ADR' | 'DOC';
|
|
9
|
+
path: string;
|
|
10
|
+
source_finding_ref: string;
|
|
11
|
+
title: string;
|
|
12
|
+
write_scope: 'draft_only';
|
|
13
|
+
}>;
|
|
14
|
+
human_questions: NonNullable<ReversaEvidenceBundle['human_questions']>;
|
|
15
|
+
blocked_operations: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function buildReversaArtifactWritePlan(bundle: ReversaEvidenceBundle): ReversaArtifactWritePlan;
|
|
18
|
+
//# sourceMappingURL=reversa-artifact-writer.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function buildReversaArtifactWritePlan(bundle) {
|
|
2
|
+
const lowConfidenceQuestions = bundle.findings
|
|
3
|
+
.filter((finding) => finding.confidence === 'low' || finding.confidence === 'unknown')
|
|
4
|
+
.map((finding) => ({
|
|
5
|
+
id: `REV-Q-${finding.id.replace(/^REV-FIND-/u, '')}`,
|
|
6
|
+
question: `Confirm finding before promotion: ${finding.title}`,
|
|
7
|
+
blocks_phase: 'artifact_generation',
|
|
8
|
+
required_before_apply: true,
|
|
9
|
+
}));
|
|
10
|
+
const humanQuestions = [...bundle.human_questions, ...lowConfidenceQuestions];
|
|
11
|
+
return {
|
|
12
|
+
schema_version: 1,
|
|
13
|
+
contract: 'reversa-artifact-write-plan/v1',
|
|
14
|
+
feature_ref: bundle.feature_ref,
|
|
15
|
+
status: humanQuestions.some((question) => question.required_before_apply) ? 'needs_clarification' : 'ready',
|
|
16
|
+
draft_artifacts: bundle.findings.map((finding) => ({
|
|
17
|
+
artifact_type: inferArtifactType(finding.phase),
|
|
18
|
+
path: `.sdd/evidence/reversa/${bundle.feature_ref}/drafts/${finding.id.toLowerCase()}.yaml`,
|
|
19
|
+
source_finding_ref: finding.id,
|
|
20
|
+
title: finding.title,
|
|
21
|
+
write_scope: 'draft_only',
|
|
22
|
+
})),
|
|
23
|
+
human_questions: humanQuestions,
|
|
24
|
+
blocked_operations: [
|
|
25
|
+
'write .sdd/state directly',
|
|
26
|
+
'promote drafts without CodeSDD lifecycle command',
|
|
27
|
+
'apply generated artifacts before required human questions are resolved',
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function inferArtifactType(phase) {
|
|
32
|
+
if (phase === 'artifact_generation')
|
|
33
|
+
return 'FEAT';
|
|
34
|
+
if (phase === 'migration' || phase === 'reconstruction' || phase === 'equivalence')
|
|
35
|
+
return 'ADR';
|
|
36
|
+
if (phase === 'rules' || phase === 'architecture')
|
|
37
|
+
return 'DEB';
|
|
38
|
+
return 'DOC';
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=reversa-artifact-writer.js.map
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export declare const REVERSA_COMMANDS: readonly ["intake", "scan", "extract", "ask", "plan", "generate", "validate", "reconstruct", "report", "url"];
|
|
2
|
+
export declare const REVERSA_MODES: readonly ["read-only", "plan", "validate", "apply-sandbox", "apply-approved"];
|
|
3
|
+
export declare const REVERSA_URL_MODES: readonly ["authorized-replica", "authorized-derivative", "clean-room-style"];
|
|
4
|
+
export declare const REVERSA_AUTHORIZATION_SCOPES: readonly ["owner", "client-authorized", "licensed", "clean-room"];
|
|
5
|
+
export declare const REVERSA_VOLUME_PRESETS: readonly ["small", "standard", "large"];
|
|
6
|
+
export declare const REVERSA_TARGET_STACKS: readonly ["react", "nextjs", "angular", "vue", "svelte", "html"];
|
|
7
|
+
export declare const REVERSA_PRESERVATION_CHOICES: readonly ["yes", "no", "ask"];
|
|
8
|
+
export declare const REVERSA_BACKEND_CONTRACT_MODES: readonly ["none", "inventory", "plan"];
|
|
9
|
+
export type ReversaCommand = (typeof REVERSA_COMMANDS)[number];
|
|
10
|
+
export type ReversaMode = (typeof REVERSA_MODES)[number];
|
|
11
|
+
export type ReversaUrlMode = (typeof REVERSA_URL_MODES)[number];
|
|
12
|
+
export type ReversaAuthorizationScope = (typeof REVERSA_AUTHORIZATION_SCOPES)[number];
|
|
13
|
+
export type ReversaVolumePreset = (typeof REVERSA_VOLUME_PRESETS)[number];
|
|
14
|
+
export type ReversaTargetStack = (typeof REVERSA_TARGET_STACKS)[number];
|
|
15
|
+
export type ReversaPreservationChoice = (typeof REVERSA_PRESERVATION_CHOICES)[number];
|
|
16
|
+
export type ReversaBackendContractMode = (typeof REVERSA_BACKEND_CONTRACT_MODES)[number];
|
|
17
|
+
export type ReversaPolicyStatus = 'allowed' | 'blocked';
|
|
18
|
+
export interface BuildReversaCommandPlanInput {
|
|
19
|
+
command: string;
|
|
20
|
+
mode?: string;
|
|
21
|
+
executionMode?: string;
|
|
22
|
+
target?: string;
|
|
23
|
+
featureRef?: string;
|
|
24
|
+
sourcePath?: string;
|
|
25
|
+
approvals?: string[];
|
|
26
|
+
urlMode?: string;
|
|
27
|
+
acceptLegalTerms?: boolean;
|
|
28
|
+
authorizationScope?: string;
|
|
29
|
+
authorizationNote?: string;
|
|
30
|
+
volumePreset?: string;
|
|
31
|
+
volumeBudgetPath?: string;
|
|
32
|
+
volumeBudgetApproved?: boolean;
|
|
33
|
+
targetStack?: string;
|
|
34
|
+
preserveBrand?: string;
|
|
35
|
+
preserveLogo?: string;
|
|
36
|
+
preserveContent?: string;
|
|
37
|
+
preserveAssets?: string;
|
|
38
|
+
preserveUniqueTraits?: string;
|
|
39
|
+
backendContracts?: string;
|
|
40
|
+
backendRedactionPolicy?: string;
|
|
41
|
+
brandTransform?: string;
|
|
42
|
+
intakePath?: string;
|
|
43
|
+
intakeSchemaValidated?: boolean;
|
|
44
|
+
acknowledgeFrontendOnly?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ReversaCommandPlan {
|
|
47
|
+
schema_version: 'reversa-command-plan/v1';
|
|
48
|
+
command: ReversaCommand;
|
|
49
|
+
mode: ReversaMode;
|
|
50
|
+
status: ReversaPolicyStatus;
|
|
51
|
+
feature_ref: string | null;
|
|
52
|
+
source_path: string | null;
|
|
53
|
+
evidence_path: string;
|
|
54
|
+
allowed_operations: string[];
|
|
55
|
+
blocked_operations: string[];
|
|
56
|
+
required_contracts: string[];
|
|
57
|
+
warnings: string[];
|
|
58
|
+
url_policy: ReversaUrlPolicyPlan | null;
|
|
59
|
+
policy: {
|
|
60
|
+
read_only_default: boolean;
|
|
61
|
+
hostile_input_boundary: boolean;
|
|
62
|
+
no_direct_sdd_state_writes: boolean;
|
|
63
|
+
approval_required_for_apply: boolean;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export interface ReversaUrlPolicyPlan {
|
|
67
|
+
target_url: string | null;
|
|
68
|
+
url_mode: ReversaUrlMode;
|
|
69
|
+
legal_terms_accepted: boolean;
|
|
70
|
+
authorization_scope: ReversaAuthorizationScope | null;
|
|
71
|
+
authorization_note_present: boolean;
|
|
72
|
+
guided_intake_required: boolean;
|
|
73
|
+
intake_path: string | null;
|
|
74
|
+
target_stack: ReversaTargetStack | null;
|
|
75
|
+
preserve_brand: ReversaPreservationChoice | null;
|
|
76
|
+
preserve_logo: ReversaPreservationChoice | null;
|
|
77
|
+
preserve_content: ReversaPreservationChoice | null;
|
|
78
|
+
preserve_assets: ReversaPreservationChoice | null;
|
|
79
|
+
preserve_unique_traits_present: boolean;
|
|
80
|
+
brand_transform_present: boolean;
|
|
81
|
+
backend_contracts: ReversaBackendContractMode;
|
|
82
|
+
backend_redaction_policy_present: boolean;
|
|
83
|
+
frontend_only_boundary: true;
|
|
84
|
+
frontend_only_acknowledged: boolean;
|
|
85
|
+
backend_implementation_copied: false;
|
|
86
|
+
volume_preset: ReversaVolumePreset;
|
|
87
|
+
volume_budget_path: string | null;
|
|
88
|
+
volume_budget_approved: boolean;
|
|
89
|
+
volume_limits: ReversaVolumeLimits;
|
|
90
|
+
required_questions: string[];
|
|
91
|
+
blocked_reasons: string[];
|
|
92
|
+
required_evidence: string[];
|
|
93
|
+
conditional_evidence: string[];
|
|
94
|
+
optional_evidence: string[];
|
|
95
|
+
qa_thresholds: {
|
|
96
|
+
viewports: string[];
|
|
97
|
+
authorized_replica: {
|
|
98
|
+
aggregate_visual_similarity_percent: number;
|
|
99
|
+
critical_component_similarity_percent: number;
|
|
100
|
+
average_layout_drift_px: number;
|
|
101
|
+
};
|
|
102
|
+
authorized_derivative: {
|
|
103
|
+
structural_correspondence_percent: number;
|
|
104
|
+
protected_identity_distance_percent: number;
|
|
105
|
+
};
|
|
106
|
+
clean_room_style: {
|
|
107
|
+
aggregate_visual_similarity_ceiling_percent: number;
|
|
108
|
+
protected_identity_reuse_allowed: number;
|
|
109
|
+
};
|
|
110
|
+
replay_diff_budget_percent: number;
|
|
111
|
+
};
|
|
112
|
+
data_lifecycle: {
|
|
113
|
+
default_retention_days: number;
|
|
114
|
+
purge_by_run_id_required: boolean;
|
|
115
|
+
terms_and_intake_hash_required: boolean;
|
|
116
|
+
redact_secrets_and_pii: boolean;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export interface ReversaVolumeLimits {
|
|
120
|
+
max_pages: number;
|
|
121
|
+
max_crawl_depth: number;
|
|
122
|
+
max_same_domain_links_queued: number;
|
|
123
|
+
max_dom_nodes_per_page: number;
|
|
124
|
+
max_css_rules: number;
|
|
125
|
+
max_assets_fetched: number;
|
|
126
|
+
max_total_download_mb: number;
|
|
127
|
+
max_single_asset_mb: number;
|
|
128
|
+
max_screenshots: number;
|
|
129
|
+
max_viewports: number;
|
|
130
|
+
max_generated_files: number;
|
|
131
|
+
max_analysis_tokens: number;
|
|
132
|
+
request_rate_per_second: number;
|
|
133
|
+
timeout_seconds: number;
|
|
134
|
+
}
|
|
135
|
+
export declare function buildReversaCommandPlan(input: BuildReversaCommandPlanInput): ReversaCommandPlan;
|
|
136
|
+
//# sourceMappingURL=reversa-command-policy.d.ts.map
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
export const REVERSA_COMMANDS = [
|
|
2
|
+
'intake',
|
|
3
|
+
'scan',
|
|
4
|
+
'extract',
|
|
5
|
+
'ask',
|
|
6
|
+
'plan',
|
|
7
|
+
'generate',
|
|
8
|
+
'validate',
|
|
9
|
+
'reconstruct',
|
|
10
|
+
'report',
|
|
11
|
+
'url',
|
|
12
|
+
];
|
|
13
|
+
export const REVERSA_MODES = ['read-only', 'plan', 'validate', 'apply-sandbox', 'apply-approved'];
|
|
14
|
+
export const REVERSA_URL_MODES = ['authorized-replica', 'authorized-derivative', 'clean-room-style'];
|
|
15
|
+
export const REVERSA_AUTHORIZATION_SCOPES = ['owner', 'client-authorized', 'licensed', 'clean-room'];
|
|
16
|
+
export const REVERSA_VOLUME_PRESETS = ['small', 'standard', 'large'];
|
|
17
|
+
export const REVERSA_TARGET_STACKS = ['react', 'nextjs', 'angular', 'vue', 'svelte', 'html'];
|
|
18
|
+
export const REVERSA_PRESERVATION_CHOICES = ['yes', 'no', 'ask'];
|
|
19
|
+
export const REVERSA_BACKEND_CONTRACT_MODES = ['none', 'inventory', 'plan'];
|
|
20
|
+
const REVERSA_VOLUME_LIMITS = {
|
|
21
|
+
small: {
|
|
22
|
+
max_pages: 1,
|
|
23
|
+
max_crawl_depth: 0,
|
|
24
|
+
max_same_domain_links_queued: 5,
|
|
25
|
+
max_dom_nodes_per_page: 8000,
|
|
26
|
+
max_css_rules: 2000,
|
|
27
|
+
max_assets_fetched: 30,
|
|
28
|
+
max_total_download_mb: 25,
|
|
29
|
+
max_single_asset_mb: 5,
|
|
30
|
+
max_screenshots: 3,
|
|
31
|
+
max_viewports: 1,
|
|
32
|
+
max_generated_files: 40,
|
|
33
|
+
max_analysis_tokens: 80000,
|
|
34
|
+
request_rate_per_second: 1,
|
|
35
|
+
timeout_seconds: 45,
|
|
36
|
+
},
|
|
37
|
+
standard: {
|
|
38
|
+
max_pages: 5,
|
|
39
|
+
max_crawl_depth: 1,
|
|
40
|
+
max_same_domain_links_queued: 25,
|
|
41
|
+
max_dom_nodes_per_page: 20000,
|
|
42
|
+
max_css_rules: 8000,
|
|
43
|
+
max_assets_fetched: 120,
|
|
44
|
+
max_total_download_mb: 100,
|
|
45
|
+
max_single_asset_mb: 15,
|
|
46
|
+
max_screenshots: 9,
|
|
47
|
+
max_viewports: 3,
|
|
48
|
+
max_generated_files: 160,
|
|
49
|
+
max_analysis_tokens: 250000,
|
|
50
|
+
request_rate_per_second: 1,
|
|
51
|
+
timeout_seconds: 120,
|
|
52
|
+
},
|
|
53
|
+
large: {
|
|
54
|
+
max_pages: 20,
|
|
55
|
+
max_crawl_depth: 2,
|
|
56
|
+
max_same_domain_links_queued: 100,
|
|
57
|
+
max_dom_nodes_per_page: 60000,
|
|
58
|
+
max_css_rules: 25000,
|
|
59
|
+
max_assets_fetched: 400,
|
|
60
|
+
max_total_download_mb: 500,
|
|
61
|
+
max_single_asset_mb: 50,
|
|
62
|
+
max_screenshots: 30,
|
|
63
|
+
max_viewports: 5,
|
|
64
|
+
max_generated_files: 600,
|
|
65
|
+
max_analysis_tokens: 900000,
|
|
66
|
+
request_rate_per_second: 2,
|
|
67
|
+
timeout_seconds: 300,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const REQUIRED_URL_EVIDENCE = [
|
|
71
|
+
'terms-acceptance.yaml',
|
|
72
|
+
'authorization-attestation.yaml',
|
|
73
|
+
'guided-intake.yaml',
|
|
74
|
+
'brand-uniqueness-decision.yaml',
|
|
75
|
+
'target-technology-decision.yaml',
|
|
76
|
+
'frontend-backend-boundary-report.yaml',
|
|
77
|
+
'volumetry-report.yaml',
|
|
78
|
+
'external-tool-research.md',
|
|
79
|
+
'capture-manifest.yaml',
|
|
80
|
+
'dom-snapshot-summary.yaml',
|
|
81
|
+
'computed-style-inventory.yaml',
|
|
82
|
+
'asset-policy-report.yaml',
|
|
83
|
+
'design-tokens.dtcg.json',
|
|
84
|
+
'style-dictionary.config.json',
|
|
85
|
+
'section-map.yaml',
|
|
86
|
+
'component-map.yaml',
|
|
87
|
+
'brand-policy-report.yaml',
|
|
88
|
+
'responsive-diff-report.yaml',
|
|
89
|
+
'visual-fidelity-score.yaml',
|
|
90
|
+
'similarity-distance-report.yaml',
|
|
91
|
+
'human-approval.yaml',
|
|
92
|
+
'generated-artifact-map.yaml',
|
|
93
|
+
];
|
|
94
|
+
const CONDITIONAL_URL_EVIDENCE = ['interaction-state-report.yaml', 'backend-contract-inventory.yaml'];
|
|
95
|
+
const OPTIONAL_URL_EVIDENCE = [];
|
|
96
|
+
function parseReversaCommand(command) {
|
|
97
|
+
if (REVERSA_COMMANDS.includes(command)) {
|
|
98
|
+
return command;
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Invalid Reversa command. Use one of: ${REVERSA_COMMANDS.join(', ')}.`);
|
|
101
|
+
}
|
|
102
|
+
function parseReversaMode(mode) {
|
|
103
|
+
const candidate = mode ?? 'read-only';
|
|
104
|
+
if (REVERSA_MODES.includes(candidate)) {
|
|
105
|
+
return candidate;
|
|
106
|
+
}
|
|
107
|
+
throw new Error(`Invalid Reversa mode. Use one of: ${REVERSA_MODES.join(', ')}.`);
|
|
108
|
+
}
|
|
109
|
+
function isUrlMode(value) {
|
|
110
|
+
return Boolean(value && REVERSA_URL_MODES.includes(value));
|
|
111
|
+
}
|
|
112
|
+
function parseUrlMode(mode) {
|
|
113
|
+
const candidate = mode ?? 'clean-room-style';
|
|
114
|
+
if (REVERSA_URL_MODES.includes(candidate)) {
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
throw new Error(`Invalid Reversa URL mode. Use one of: ${REVERSA_URL_MODES.join(', ')}.`);
|
|
118
|
+
}
|
|
119
|
+
function parseOptionalEnum(value, values, label) {
|
|
120
|
+
if (!value)
|
|
121
|
+
return null;
|
|
122
|
+
if (values.includes(value)) {
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`Invalid ${label}. Use one of: ${values.join(', ')}.`);
|
|
126
|
+
}
|
|
127
|
+
function parseEnumWithDefault(value, values, label, fallback) {
|
|
128
|
+
return parseOptionalEnum(value, values, label) ?? fallback;
|
|
129
|
+
}
|
|
130
|
+
function normalizedApprovals(approvals) {
|
|
131
|
+
return new Set((approvals ?? []).map((approval) => approval.trim().toLowerCase()).filter(Boolean));
|
|
132
|
+
}
|
|
133
|
+
function evidenceRef(featureRef, command) {
|
|
134
|
+
return `.sdd/evidence/reversa/${featureRef || 'UNSCOPED'}/${command}-command-plan.yaml`;
|
|
135
|
+
}
|
|
136
|
+
function parseHttpUrl(target) {
|
|
137
|
+
if (!target)
|
|
138
|
+
return null;
|
|
139
|
+
try {
|
|
140
|
+
const parsed = new URL(target);
|
|
141
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
142
|
+
throw new Error('unsupported protocol');
|
|
143
|
+
}
|
|
144
|
+
return parsed.toString();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
throw new Error('Invalid Reversa URL target. Use an absolute http or https URL.');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function buildReversaUrlPolicyPlan(input) {
|
|
151
|
+
const urlMode = parseUrlMode(input.urlMode ?? (isUrlMode(input.mode) ? input.mode : undefined));
|
|
152
|
+
const authorizationScope = parseOptionalEnum(input.authorizationScope, REVERSA_AUTHORIZATION_SCOPES, 'authorization scope');
|
|
153
|
+
const volumePreset = parseEnumWithDefault(input.volumePreset, REVERSA_VOLUME_PRESETS, 'volume preset', 'small');
|
|
154
|
+
const targetStack = parseOptionalEnum(input.targetStack, REVERSA_TARGET_STACKS, 'target stack');
|
|
155
|
+
const preserveBrand = parseOptionalEnum(input.preserveBrand, REVERSA_PRESERVATION_CHOICES, 'preserve brand decision');
|
|
156
|
+
const preserveLogo = parseOptionalEnum(input.preserveLogo, REVERSA_PRESERVATION_CHOICES, 'preserve logo decision');
|
|
157
|
+
const preserveContent = parseOptionalEnum(input.preserveContent, REVERSA_PRESERVATION_CHOICES, 'preserve content decision');
|
|
158
|
+
const preserveAssets = parseOptionalEnum(input.preserveAssets, REVERSA_PRESERVATION_CHOICES, 'preserve assets decision');
|
|
159
|
+
const backendContracts = parseEnumWithDefault(input.backendContracts, REVERSA_BACKEND_CONTRACT_MODES, 'backend contracts mode', 'none');
|
|
160
|
+
const requiredQuestions = [];
|
|
161
|
+
const blockedReasons = [];
|
|
162
|
+
const targetUrl = parseHttpUrl(input.target);
|
|
163
|
+
const notePresent = Boolean(input.authorizationNote?.trim());
|
|
164
|
+
const uniqueTraitsPresent = Boolean(input.preserveUniqueTraits?.trim());
|
|
165
|
+
if (!targetUrl) {
|
|
166
|
+
blockedReasons.push('URL target is required for Reversa URL planning.');
|
|
167
|
+
}
|
|
168
|
+
if (!input.acceptLegalTerms) {
|
|
169
|
+
blockedReasons.push('URL flow requires --accept-legal-terms before any collection.');
|
|
170
|
+
}
|
|
171
|
+
if (!authorizationScope) {
|
|
172
|
+
blockedReasons.push('URL flow requires --authorization-scope.');
|
|
173
|
+
}
|
|
174
|
+
if (!notePresent) {
|
|
175
|
+
blockedReasons.push('URL flow requires a non-empty --authorization-note for auditability.');
|
|
176
|
+
}
|
|
177
|
+
if (!input.acknowledgeFrontendOnly) {
|
|
178
|
+
blockedReasons.push('URL flow requires --ack-frontend-only to acknowledge that backend implementation is not copied.');
|
|
179
|
+
}
|
|
180
|
+
if (input.volumeBudgetPath && !input.volumeBudgetApproved) {
|
|
181
|
+
blockedReasons.push('Custom volume budget requires --approve-volume-budget after schema/human approval.');
|
|
182
|
+
}
|
|
183
|
+
if (input.intakePath && !input.intakeSchemaValidated) {
|
|
184
|
+
blockedReasons.push('Non-interactive --intake requires --intake-schema-validated.');
|
|
185
|
+
}
|
|
186
|
+
if (!input.intakePath) {
|
|
187
|
+
if (!targetStack) {
|
|
188
|
+
requiredQuestions.push('Which target stack should be generated: react, nextjs, angular, vue, svelte, or html?');
|
|
189
|
+
blockedReasons.push('Guided intake requires --target-stack or --intake.');
|
|
190
|
+
}
|
|
191
|
+
if (!preserveBrand || preserveBrand === 'ask') {
|
|
192
|
+
requiredQuestions.push('Should the new output preserve the same brand name?');
|
|
193
|
+
blockedReasons.push('Guided intake requires an explicit --preserve-brand yes|no decision or --intake.');
|
|
194
|
+
}
|
|
195
|
+
if (!preserveLogo || preserveLogo === 'ask') {
|
|
196
|
+
requiredQuestions.push('Should the same logo be reused, replaced, or omitted?');
|
|
197
|
+
blockedReasons.push('Guided intake requires an explicit --preserve-logo yes|no decision or --intake.');
|
|
198
|
+
}
|
|
199
|
+
if (!preserveContent || preserveContent === 'ask') {
|
|
200
|
+
requiredQuestions.push('Should headings, copy, labels, and text content be reused, rewritten, or replaced?');
|
|
201
|
+
blockedReasons.push('Guided intake requires an explicit --preserve-content yes|no decision or --intake.');
|
|
202
|
+
}
|
|
203
|
+
if (!preserveAssets || preserveAssets === 'ask') {
|
|
204
|
+
requiredQuestions.push('Should images, media, icons, fonts, and third-party assets be reused, replaced, or omitted?');
|
|
205
|
+
blockedReasons.push('Guided intake requires an explicit --preserve-assets yes|no decision or --intake.');
|
|
206
|
+
}
|
|
207
|
+
if (!uniqueTraitsPresent) {
|
|
208
|
+
requiredQuestions.push('Which unique product traits must be preserved or intentionally changed?');
|
|
209
|
+
blockedReasons.push('Guided intake requires --preserve-unique-traits or --intake.');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (urlMode === 'clean-room-style' && preserveLogo === 'yes') {
|
|
213
|
+
blockedReasons.push('clean-room-style cannot preserve the source logo.');
|
|
214
|
+
}
|
|
215
|
+
if (urlMode === 'clean-room-style' && preserveBrand === 'yes') {
|
|
216
|
+
blockedReasons.push('clean-room-style cannot preserve the source brand name.');
|
|
217
|
+
}
|
|
218
|
+
if (urlMode === 'clean-room-style' && preserveContent === 'yes') {
|
|
219
|
+
blockedReasons.push('clean-room-style cannot preserve source copy/content.');
|
|
220
|
+
}
|
|
221
|
+
if (urlMode === 'clean-room-style' && preserveAssets === 'yes') {
|
|
222
|
+
blockedReasons.push('clean-room-style cannot preserve source protected assets.');
|
|
223
|
+
}
|
|
224
|
+
if (urlMode === 'authorized-replica' && authorizationScope === 'clean-room') {
|
|
225
|
+
blockedReasons.push('authorized-replica requires owner, client-authorized, or licensed scope.');
|
|
226
|
+
}
|
|
227
|
+
if (backendContracts !== 'none') {
|
|
228
|
+
requiredQuestions.push('Backend implementation will not be copied; only redacted observed request contracts may be inventoried.');
|
|
229
|
+
if (!input.backendRedactionPolicy?.trim()) {
|
|
230
|
+
blockedReasons.push('Backend contract inventory requires --backend-redaction-policy.');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
target_url: targetUrl,
|
|
235
|
+
url_mode: urlMode,
|
|
236
|
+
legal_terms_accepted: Boolean(input.acceptLegalTerms),
|
|
237
|
+
authorization_scope: authorizationScope,
|
|
238
|
+
authorization_note_present: notePresent,
|
|
239
|
+
guided_intake_required: true,
|
|
240
|
+
intake_path: input.intakePath ?? null,
|
|
241
|
+
target_stack: targetStack,
|
|
242
|
+
preserve_brand: preserveBrand,
|
|
243
|
+
preserve_logo: preserveLogo,
|
|
244
|
+
preserve_content: preserveContent,
|
|
245
|
+
preserve_assets: preserveAssets,
|
|
246
|
+
preserve_unique_traits_present: uniqueTraitsPresent,
|
|
247
|
+
brand_transform_present: Boolean(input.brandTransform?.trim()),
|
|
248
|
+
backend_contracts: backendContracts,
|
|
249
|
+
backend_redaction_policy_present: Boolean(input.backendRedactionPolicy?.trim()),
|
|
250
|
+
frontend_only_boundary: true,
|
|
251
|
+
frontend_only_acknowledged: Boolean(input.acknowledgeFrontendOnly),
|
|
252
|
+
backend_implementation_copied: false,
|
|
253
|
+
volume_preset: volumePreset,
|
|
254
|
+
volume_budget_path: input.volumeBudgetPath ?? null,
|
|
255
|
+
volume_budget_approved: Boolean(input.volumeBudgetApproved),
|
|
256
|
+
volume_limits: REVERSA_VOLUME_LIMITS[volumePreset],
|
|
257
|
+
required_questions: requiredQuestions,
|
|
258
|
+
blocked_reasons: [...new Set(blockedReasons)],
|
|
259
|
+
required_evidence: [...REQUIRED_URL_EVIDENCE],
|
|
260
|
+
conditional_evidence: backendContracts === 'none'
|
|
261
|
+
? CONDITIONAL_URL_EVIDENCE.filter((artifact) => artifact !== 'backend-contract-inventory.yaml')
|
|
262
|
+
: [...CONDITIONAL_URL_EVIDENCE],
|
|
263
|
+
optional_evidence: [...OPTIONAL_URL_EVIDENCE],
|
|
264
|
+
qa_thresholds: {
|
|
265
|
+
viewports: ['390x844', '768x1024', '1440x900'],
|
|
266
|
+
authorized_replica: {
|
|
267
|
+
aggregate_visual_similarity_percent: 95,
|
|
268
|
+
critical_component_similarity_percent: 97,
|
|
269
|
+
average_layout_drift_px: 8,
|
|
270
|
+
},
|
|
271
|
+
authorized_derivative: {
|
|
272
|
+
structural_correspondence_percent: 80,
|
|
273
|
+
protected_identity_distance_percent: 25,
|
|
274
|
+
},
|
|
275
|
+
clean_room_style: {
|
|
276
|
+
aggregate_visual_similarity_ceiling_percent: 70,
|
|
277
|
+
protected_identity_reuse_allowed: 0,
|
|
278
|
+
},
|
|
279
|
+
replay_diff_budget_percent: 2,
|
|
280
|
+
},
|
|
281
|
+
data_lifecycle: {
|
|
282
|
+
default_retention_days: 30,
|
|
283
|
+
purge_by_run_id_required: true,
|
|
284
|
+
terms_and_intake_hash_required: true,
|
|
285
|
+
redact_secrets_and_pii: true,
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
export function buildReversaCommandPlan(input) {
|
|
290
|
+
const command = parseReversaCommand(input.command);
|
|
291
|
+
const mode = parseReversaMode(input.executionMode ?? (command === 'url' && isUrlMode(input.mode) ? undefined : input.mode));
|
|
292
|
+
const approvals = normalizedApprovals(input.approvals);
|
|
293
|
+
const allowedOperations = ['inspect capability contract', 'emit governed command plan'];
|
|
294
|
+
const blockedOperations = ['write .sdd/state directly', 'persist generated artifacts without downstream evidence schema'];
|
|
295
|
+
const requiredContracts = ['FEAT-0406 capability baseline'];
|
|
296
|
+
const warnings = [];
|
|
297
|
+
let urlPolicy = null;
|
|
298
|
+
let status = 'allowed';
|
|
299
|
+
if (!input.featureRef) {
|
|
300
|
+
warnings.push('No FEAT reference supplied; evidence is scoped to UNSCOPED until lifecycle context is provided.');
|
|
301
|
+
}
|
|
302
|
+
if (command === 'url') {
|
|
303
|
+
urlPolicy = buildReversaUrlPolicyPlan(input);
|
|
304
|
+
requiredContracts.push('EPIC-0092 Reversa URL legal and guided-intake contract', 'FEAT-0424 legal acceptance gate', 'FEAT-0425 guided intake contract', 'FEAT-0426 volumetry budget contract', 'FEAT-0430 frontend/backend boundary contract', 'FEAT-0431 visual QA threshold contract');
|
|
305
|
+
allowedOperations.push('emit Reversa URL governed preflight plan');
|
|
306
|
+
blockedOperations.push('capture URL before legal terms, authorization, guided intake, volume budget, and frontend/backend boundary are accepted', 'copy backend implementation, credentials, databases, private APIs, or server-side business rules');
|
|
307
|
+
warnings.push('Reversa URL output is frontend/rendered-experience only; backend implementation is not copied.');
|
|
308
|
+
warnings.push('Observed backend requests can only become redacted contracts for a separate backend plan.');
|
|
309
|
+
if (urlPolicy.blocked_reasons.length > 0) {
|
|
310
|
+
status = 'blocked';
|
|
311
|
+
warnings.push(...urlPolicy.blocked_reasons);
|
|
312
|
+
}
|
|
313
|
+
if (urlPolicy.backend_contracts !== 'none') {
|
|
314
|
+
requiredContracts.push('redacted backend-contract inventory policy');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (mode === 'validate') {
|
|
318
|
+
allowedOperations.push('validate evidence bundle shape once FEAT-0408 is available');
|
|
319
|
+
requiredContracts.push('FEAT-0408 evidence bundle schemas');
|
|
320
|
+
}
|
|
321
|
+
if (mode === 'apply-sandbox') {
|
|
322
|
+
allowedOperations.push('plan sandbox-only writes once FEAT-0415 and FEAT-0416 are available');
|
|
323
|
+
blockedOperations.push('write outside temporary or explicitly approved sandbox roots');
|
|
324
|
+
requiredContracts.push('FEAT-0415 artifact generation dry-run contract', 'FEAT-0416 reconstruction contract');
|
|
325
|
+
}
|
|
326
|
+
if (mode === 'apply-approved') {
|
|
327
|
+
requiredContracts.push('human approval record', 'FEAT-0416 rollback contract', 'FEAT-0417 equivalence gate');
|
|
328
|
+
if (!approvals.has('reversa-apply') && !approvals.has('all')) {
|
|
329
|
+
status = 'blocked';
|
|
330
|
+
blockedOperations.push('apply approved reconstruction without explicit reversa-apply approval');
|
|
331
|
+
warnings.push('apply-approved mode requires --approval reversa-apply or --approval all.');
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
allowedOperations.push('plan approved apply after downstream rollback and equivalence evidence exists');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (mode === 'read-only' || mode === 'plan') {
|
|
338
|
+
blockedOperations.push('mutate project files');
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
schema_version: 'reversa-command-plan/v1',
|
|
342
|
+
command,
|
|
343
|
+
mode,
|
|
344
|
+
status,
|
|
345
|
+
feature_ref: input.featureRef ?? null,
|
|
346
|
+
source_path: input.sourcePath ?? null,
|
|
347
|
+
evidence_path: evidenceRef(input.featureRef, command),
|
|
348
|
+
allowed_operations: allowedOperations,
|
|
349
|
+
blocked_operations: blockedOperations,
|
|
350
|
+
required_contracts: requiredContracts,
|
|
351
|
+
warnings,
|
|
352
|
+
url_policy: urlPolicy,
|
|
353
|
+
policy: {
|
|
354
|
+
read_only_default: true,
|
|
355
|
+
hostile_input_boundary: true,
|
|
356
|
+
no_direct_sdd_state_writes: true,
|
|
357
|
+
approval_required_for_apply: true,
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=reversa-command-policy.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReversaEvidenceBundle } from './reversa-evidence.js';
|
|
2
|
+
export declare function buildReversaDataLineage(input: {
|
|
3
|
+
featureRef: string;
|
|
4
|
+
operationId: string;
|
|
5
|
+
generatedAt: string;
|
|
6
|
+
sources: Array<{
|
|
7
|
+
path: string;
|
|
8
|
+
content: string;
|
|
9
|
+
}>;
|
|
10
|
+
}): ReversaEvidenceBundle;
|
|
11
|
+
//# sourceMappingURL=reversa-data-extractor.d.ts.map
|