Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ jobs:
- name: Lint
run: npm --prefix apps/marketing run lint

- name: Capability parity
run: npm --prefix apps/marketing test

- name: Typecheck
run: npm --prefix apps/marketing run typecheck

Expand Down
3 changes: 2 additions & 1 deletion apps/marketing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"build": "tsc -b && vite build",
"preview": "vite preview",
"lint": "eslint .",
"typecheck": "tsc -b --noEmit"
"typecheck": "tsc -b --noEmit",
"test": "node --test tests/capability-parity.test.mjs"
},
"dependencies": {
"clsx": "^2.1.1",
Expand Down
2 changes: 1 addition & 1 deletion apps/marketing/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useLandingTheme } from '@/hooks/useLandingTheme';
*
* The two hero calls to action open full-screen panels over the page rather
* than navigating away: "See how it works" runs a scripted walkthrough of a
* real analysis, and "Analyze a Repository" shows how to run PARTHA against
* fictional interface and proposed checks, and "Analyze a Repository" shows how to run PARTHA against
* your own code. Closing either returns the reader exactly where they were.
*/
export function App() {
Expand Down
9 changes: 4 additions & 5 deletions apps/marketing/src/components/DemoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export function DemoModal({ onClose }: { onClose: () => void }) {
Scripted simulation · sample repository
</div>
<h2 id="demo-modal-title" className="font-display text-2xl font-semibold text-foreground">
See what a PARTHA analysis produces
Explore the review interface and proposed checks
</h2>
<p className="mt-2 max-w-xl text-sm leading-relaxed text-muted-foreground">
A scripted walkthrough of a made-up sample repository ({SAMPLE_REPO.name}) -- not a live analysis of any
real code. It uses PARTHA's actual finding categories and output shape.
real code. The four checks below are proposed and unimplemented. Categories describe current coverage; all metrics and source spans are fictional.
</p>
</div>
</div>
Expand Down Expand Up @@ -102,8 +102,7 @@ export function DemoModal({ onClose }: { onClose: () => void }) {
{phase === 'idle' && (
<div className="flex flex-col items-center gap-4 px-6 py-16 text-center">
<p className="max-w-sm text-sm text-muted-foreground">
Run the simulation to watch PARTHA walk through a sample repository and produce Engineering Review
and Repository Insights output.
Run the interface simulation to explore fictional metrics and proposed review checks.
</p>
<button
type="button"
Expand Down Expand Up @@ -185,7 +184,7 @@ export function DemoModal({ onClose }: { onClose: () => void }) {
</span>
</div>
<p className="mt-1 text-2xs font-medium uppercase tracking-wide text-muted-foreground">
{CATEGORY_LABELS[finding.category]}
{CATEGORY_LABELS[finding.category]} · Proposed check (not implemented)
</p>
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">{finding.explanation}</p>
<p className="mt-2 text-sm leading-relaxed text-foreground">
Expand Down
34 changes: 16 additions & 18 deletions apps/marketing/src/data/sampleAnalysis.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
/**
* Canned data for the scripted product simulation (#382).
*
* Every category id, severity level, and field name here matches the real
* product's actual Engineering Review / Repository Insights response shape
* (apps/backend/app/schemas -- cross-checked against
* apps/frontend/src/shared/services/api/generated.ts, the generated OpenAPI
* types) and the real category labels
* (apps/backend/app/review/review_service.py's `_CATEGORY_LABELS`). The
* repository, findings, and numbers themselves are entirely made up for a
* fictional sample repo -- nothing here is captured from a real analysis.
/** Fictional interface simulation. Category labels and coverage states mirror
* the current review contract; the explicitly proposed checks are unimplemented.
* Metrics, source spans and repository details are made up, not analyzer output.
*/

export const SAMPLE_REPO = {
Expand All @@ -22,7 +14,7 @@ export const SIMULATION_STEPS = [
'Extracting structural facts (Python, TypeScript)',
'Resolving module and dependency relationships',
'Sealing the ri.v1 snapshot',
'Running Engineering Review and Repository Insights',
'Showing proposed review checks and fictional Repository Insights',
] as const;

export type ReviewSeverity = 'info' | 'low' | 'medium' | 'high' | 'critical';
Expand Down Expand Up @@ -53,6 +45,7 @@ export const CATEGORY_LABELS: Record<ReviewCategoryId, string> = {

export interface SampleFinding {
id: string;
implementation: 'proposed';
title: string;
category: ReviewCategoryId;
severity: ReviewSeverity;
Expand All @@ -63,9 +56,11 @@ export interface SampleFinding {
endLine: number;
}

// These proposed checks are not emitted by the current Engineering Review rules.
export const SAMPLE_FINDINGS: SampleFinding[] = [
{
id: 'finding-1',
implementation: 'proposed',
title: 'Payment adapter imports directly from the checkout domain layer',
category: 'architecture_boundaries',
severity: 'medium',
Expand All @@ -79,6 +74,7 @@ export const SAMPLE_FINDINGS: SampleFinding[] = [
},
{
id: 'finding-2',
implementation: 'proposed',
title: 'Declared dependency pin resolves to a version not requested anywhere',
category: 'dependency_declarations',
severity: 'low',
Expand All @@ -91,18 +87,20 @@ export const SAMPLE_FINDINGS: SampleFinding[] = [
},
{
id: 'finding-3',
implementation: 'proposed',
title: 'Session cookie is issued without an explicit SameSite attribute',
category: 'authentication_evidence',
severity: 'high',
explanation:
'src/auth/session.py sets the session cookie without a SameSite attribute, so browsers fall back to a permissive default that varies by browser rather than an explicit, reviewable policy.',
'src/auth/session.py sets the session cookie without a SameSite attribute, so browser defaults apply rather than an explicit, reviewable policy.',
remediationGuidance: 'Set SameSite explicitly (Lax or Strict) when issuing the session cookie.',
path: 'src/auth/session.py',
startLine: 47,
endLine: 52,
},
{
id: 'finding-4',
implementation: 'proposed',
title: 'Two modules independently resolve the same order-total calculation',
category: 'relationship_resolution',
severity: 'info',
Expand All @@ -124,13 +122,13 @@ export interface SampleCategoryAssessment {
}

export const SAMPLE_CATEGORIES: SampleCategoryAssessment[] = [
{ id: 'architecture_boundaries', label: CATEGORY_LABELS.architecture_boundaries, state: 'assessed', findingCount: 1, explanation: 'Module boundaries were assessed from resolved import relationships.' },
{ id: 'relationship_resolution', label: CATEGORY_LABELS.relationship_resolution, state: 'assessed', findingCount: 1, explanation: 'Cross-module relationships were assessed from resolved facts.' },
{ id: 'architecture_boundaries', label: CATEGORY_LABELS.architecture_boundaries, state: 'partially_assessed', findingCount: 0, explanation: 'Structural relationships are supported; domain boundary checks are proposed.' },
{ id: 'relationship_resolution', label: CATEGORY_LABELS.relationship_resolution, state: 'assessed', findingCount: 0, explanation: 'Cross-module relationships were assessed from resolved facts.' },
{ id: 'source_extraction', label: CATEGORY_LABELS.source_extraction, state: 'assessed', findingCount: 0, explanation: 'No source-extraction diagnostics were raised for this snapshot.' },
{ id: 'dependency_declarations', label: CATEGORY_LABELS.dependency_declarations, state: 'assessed', findingCount: 1, explanation: 'Direct declarations and lockfile pins were assessed for this snapshot.' },
{ id: 'dependency_declarations', label: CATEGORY_LABELS.dependency_declarations, state: 'partially_assessed', findingCount: 0, explanation: 'Dependency inventory is supported; lockfile reconciliation is a proposed check.' },
{ id: 'security_vulnerability_scanning', label: CATEGORY_LABELS.security_vulnerability_scanning, state: 'not_assessed', findingCount: 0, explanation: 'Vulnerability scanning is not implemented; this category is not assessed.' },
{ id: 'authentication_evidence', label: CATEGORY_LABELS.authentication_evidence, state: 'assessed', findingCount: 1, explanation: 'The supported Python/FastAPI authentication subgraph was assessed.' },
{ id: 'repository_structure', label: CATEGORY_LABELS.repository_structure, state: 'assessed', findingCount: 0, explanation: 'No repository-structure diagnostics were raised for this snapshot.' },
{ id: 'authentication_evidence', label: CATEGORY_LABELS.authentication_evidence, state: 'partially_assessed', findingCount: 0, explanation: 'Authentication inventory is partial; cookie attribute checks are proposed.' },
{ id: 'repository_structure', label: CATEGORY_LABELS.repository_structure, state: 'partially_assessed', findingCount: 0, explanation: 'No repository-structure diagnostics were raised for this snapshot.' },
{ id: 'analysis_integrity', label: CATEGORY_LABELS.analysis_integrity, state: 'assessed', findingCount: 0, explanation: 'The analysis completed with no integrity diagnostics.' },
];

Expand Down
25 changes: 25 additions & 0 deletions apps/marketing/tests/capability-parity.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { URL } from 'node:url';
import { Buffer } from 'node:buffer';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
import ts from 'typescript';
const source = readFileSync(new URL('../src/data/sampleAnalysis.ts', import.meta.url), 'utf8');
const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.ESNext } }).outputText;
const { SAMPLE_FINDINGS, SAMPLE_CATEGORIES } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
test('unsupported demo checks are explicitly proposed and never counted as analyzer findings', () => {
assert.equal(SAMPLE_FINDINGS.length, 4);
for (const finding of SAMPLE_FINDINGS) assert.equal(finding.implementation, 'proposed');
for (const category of SAMPLE_CATEGORIES) assert.equal(category.findingCount, 0);
const component = readFileSync(new URL('../src/components/DemoModal.tsx', import.meta.url), 'utf8');
assert.match(component, /Proposed check \(not implemented\)/);
assert.match(component, /four checks below are proposed and unimplemented/);
});
test('limited categories retain current backend assessment states', () => {
const backend = readFileSync(new URL('../../backend/app/review/review_service.py', import.meta.url), 'utf8');
for (const id of ['architecture_boundaries', 'dependency_declarations', 'authentication_evidence', 'repository_structure']) {
assert.equal(SAMPLE_CATEGORIES.find(category => category.id === id).state, 'partially_assessed');
assert.match(backend, new RegExp(String.raw`"${id}": \([\s\S]{0,100}"partially_assessed"`));
}
assert.equal(SAMPLE_CATEGORIES.find(category => category.id === 'security_vulnerability_scanning').state, 'not_assessed');
});
Loading