AI Initiative logoAI Initiative
Reading room / GraFOSa

GraFOSa Pipeline Framework — Advisory & Documentation

Documents the graph processing pipeline and the components that transform source material into analysable structure.

Pipeline architecture
This is the retained source text, not a new validation of its claims. Numerical results and comparative claims require the accompanying source review before public reuse.

Read the connected case study or article →

Not explicitly attributed in document header · 2026-02-27

Provenance, authorship and editorial notes

GraFOSa Pipeline Framework — Advisory & Documentation

Id

grafosa-pipeline

Project

GraFOSa

Source path

grafosa/docs/PIPELINE-FRAMEWORK.md

Source host

genesis

Source sha256

b23f90158fa267c4ad4bcf63424bf860ebd9ebabc5082d86ab7c9cd2ee593cea

Repo root

grafosa

Repo head

388b50cfb34decee9d716f7f02d01ccf53305c03

Date

2026-02-27

Author

Not explicitly attributed in document header

Document status

Pipeline architecture

Source status statement

Implemented, 843 tests passing

Summary

Documents the graph processing pipeline and the components that transform source material into analysable structure.

Topics
  • GraFOSa
  • AI Learning
  • Orchestration
  • Pipeline architecture
Related ids
  • grafosa-vision
  • grafosa-gca-decisions
  • grafosa-embedded-graph-os
Evidence concerns
  • Pipeline design is not evidence of current accuracy across languages or repositories.
  • Private source selection. Source inspection only; no fresh build, deployment or effectiveness certification.
Copy scope

Full original document, byte-identical

Copy status

copied-private-review

Format

markdown

Bytes

15001

Word count

1727

Headings
  • GraFOSa Pipeline Framework — Advisory & Documentation
  • What We Built
  • Architecture
  • Components
  • PipelineConfig (`pipeline/config.py`)
  • PipelineRunner (`pipeline/runner.py`)
  • Pre-Built Pipelines
  • Pipeline Steps
  • How This Fits in Conductor / Symphony
  • The Problem
  • Conductor Integration Pattern
  • Concrete Conductor Task Definitions
  • The Learning Pipeline Loop
  • MCP Tools (for Claude Code agents)
  • CLI Commands
  • Feature Vector Schema
  • Per-File (23 features)
  • Per-Service (4 features)
  • Per-Symbol (3 features)
  • Backward Compatibility
  • What's Next
Sensitive content review
Automated secret patterns
Email occurrences

0

Customer record terms
Limitation

Pattern scan plus editorial review; not a guarantee of no personal or proprietary material. Private copies retain source code examples, internal locations and attributions.

Attribution note

Source document attribution is preserved. Repository ownership or an agent role is not automatically authorship.

Date basis

Document header or dated filename; source may contain later updates

Source pin note

SHA-256 binds exact copied working-file bytes; repo_head is repository context, not proof that every byte is committed at that head.

Publication recommendation

Private technical reading candidate; editorial selection and claim review required before public use

GraFOSa Pipeline Framework — Advisory & Documentation

Date: 2026-02-27
Status: Implemented, 843 tests passing
Files: src/grafosa/pipeline/ (7 files), refactored intel.py + strategy.py


What We Built

A config-driven pipeline framework that sits between GraFOSa's raw graph
analysis and downstream consumers (learning pipelines, LLM agents, Conductor
workflows). It solves three problems:

1. Hardcoded thresholds — All scoring formulas, risk levels, and grading
thresholds were baked into intel.py and strategy.py. Now they're
overridable via .grafosa.yaml or programmatic PipelineConfig.

2. No structured output for automation — GraFOSa's analysis was human-readable
text. Pipelines need structured dicts (feature vectors, impact metrics,
anomaly lists) that can feed into AutoML, DataFrames, or Conductor tasks.

3. No DAG execution model — Steps had no dependency ordering. The runner
provides topological sorting so that downstream tools (Conductor, Airflow)
can adopt the same step contracts.


Architecture

                    .grafosa.yaml
                         |
                   PipelineConfig
                    (overrides)
                         |
    GraFOSa Graph -------+-------> PipelineRunner (DAG)
    (63K nodes,          |            |
     88K edges)          |            +-- Step 1: Feature Extraction
                         |            |     file, service, symbol vectors
                         |            |
                         |            +-- Step 2: Change Impact
                         |            |     blast radius, affected endpoints
                         |            |
                         |            +-- Step 3: Anomaly Detection
                         |            |     z-score outliers (config thresholds)
                         |            |
                         |            +-- Step 4: Summary Formatter
                         |                  compact output for LLM context
                         |
                         +-------> GraphIntel (L7) — config-driven scoring
                         +-------> GraphStrategy (L8) — config-driven risk

Components

PipelineConfig (pipeline/config.py)

Typed, dot-path accessible config with deep-merge over defaults:

from grafosa.pipeline import PipelineConfig

# All built-in defaults
cfg = PipelineConfig.defaults()

# Override from dict (for testing or Conductor)
cfg = PipelineConfig.from_dict({
    "scoring": {"rag_thresholds": {"green": 85}},
    "anomaly": {"z_score_threshold": 3.0},
})

# Override from .grafosa.yaml (for repo-specific tuning)
cfg = PipelineConfig.load(".grafosa.yaml")

# Dot-path access
cfg.get("scoring.section_weights.architecture")  # 0.25
cfg.get("strategy.risk_levels.critical.services") # 4

All configurable values (with current defaults):

PathDefaultUsed In
scoring.section_weights.{architecture,dependencies,...}0.25/0.20/...intel.py _finalize()
scoring.severity_penalties.{critical,error,...}15/5/1/0intel.py _score_section()
scoring.rag_thresholds.{green,amber}80/50intel.py _compute_rag()
scoring.grade_thresholds.{A,B,C,D}90/75/60/40intel.py _compute_grade()
strategy.scope.platform_wide_service_ratio0.5strategy.py _determine_scope()
strategy.scope.top_n_bottleneck3strategy.py _determine_scope()
strategy.bottleneck_top_n10strategy.py _check_bottleneck()
strategy.risk_levels.{critical,high,medium}.{services,radius}4/20, 3/10, 2/5strategy.py _risk_level()
strategy.approach_scoring.{blast,complexity,coverage,scope}_weight0.3/0.2/0.2/0.3strategy.py _score_approach()
strategy.approach_scoring.max_depth20strategy.py _score_approach()
strategy.approach_scoring.structural_cycle_boost0.1strategy.py cycle boost
anomaly.z_score_threshold2.0anomaly_detection step
anomaly.min_sample_size5anomaly_detection step
summary.max_issues20summary_formatter step
summary.max_services10summary_formatter step

PipelineRunner (pipeline/runner.py)

DAG-based step runner with Kahn's topological sort:

from grafosa.pipeline import PipelineRunner, Step, PipelineConfig

runner = PipelineRunner(config=PipelineConfig.defaults())
runner.add_step(Step(name="extract", fn=my_extract_fn))
runner.add_step(Step(name="transform", fn=my_transform_fn, depends_on=["extract"]))

result = runner.run({"code_stack": stack}, pipeline_name="my-pipeline")
# result.status: "completed" | "failed"
# result.steps[0].data: dict output from each step
# result.total_duration_ms: timing

Step contract (Conductor-compatible):

def my_step(input_data: dict, config: PipelineConfig) -> dict:
    # input_data contains initial_input + upstream step outputs keyed by name
    # return dict is passed to downstream steps
    return {"my_output": ...}

Pre-Built Pipelines

from grafosa.pipeline import build_analysis_pipeline, build_change_pipeline

# Analysis: extract → anomaly → summary
runner = build_analysis_pipeline()
result = runner.run({"code_stack": stack})

# Change impact: extract → impact + anomaly → summary
runner = build_change_pipeline()
result = runner.run({"code_stack": stack, "changed_files": ["symposium/conductor.py"]})

Pipeline Steps

StepInputOutputPurpose
extract_featurescode_stackfeatures.{file,service,symbol}, statsFeature vectors for AutoML
compute_change_impactcode_stack, changed_filesimpact_metrics, per_file_impact, affected_*Blast radius metrics
detect_anomaliesextract outputanomalies[], metric_statsZ-score outlier detection
format_summaryall upstreamsummary (compact dict)LLM-ready output

How This Fits in Conductor / Symphony

The Problem

Symphony (maestro-platform) is an AI orchestration platform with 12+ services,
6K+ files, and 88K graph edges. When Conductor orchestrates code changes across
this platform, it needs answers to:

1. "What breaks if I change symposium/conductor.py?" — change impact
2. "Is this codebase healthy enough to deploy?" — health scoring
3. "Which files are anomalous and need attention?" — anomaly detection
4. "Give me a compact summary for the LLM agent" — formatted output

Previously, these answers came from hardcoded formulas. A learning pipeline
couldn't tune the thresholds. Now it can.

Conductor Integration Pattern

Conductor Workflow
    |
    +-- Task 1: Build Graph
    |     grafosa build --config .grafosa.yaml
    |     → examples/maestro_platform_full.json
    |
    +-- Task 2: Run Analysis Pipeline
    |     input:  { code_stack, pipeline_type: "analysis" }
    |     output: { features, anomalies, summary }
    |     → feed to learning pipeline for threshold tuning
    |
    +-- Task 3: Run Change Pipeline (on PR)
    |     input:  { code_stack, changed_files: [...] }
    |     output: { impact_metrics, affected_services, summary }
    |     → gate: reject if blast_radius > threshold
    |
    +-- Task 4: Feed to Learning Pipeline
    |     input:  features (AutoML-ready dicts)
    |     output: updated config thresholds
    |     → write back to .grafosa.yaml [pipelines] section
    |
    +-- Task 5: Validate & Deploy
          grafosa validate --max-severity high <services>
          → exit 0 = pass, exit 1 = fail

Concrete Conductor Task Definitions

Task: grafosa_analysis

{
  "name": "grafosa_analysis",
  "taskReferenceName": "analyze",
  "type": "SIMPLE",
  "inputParameters": {
    "graph_path": "${build.output.graph_path}",
    "pipeline_type": "analysis"
  }
}

Conductor worker calls:

from grafosa.pipeline import build_analysis_pipeline, PipelineConfig

cfg = PipelineConfig.load(".grafosa.yaml")
runner = build_analysis_pipeline(cfg)
result = runner.run({"code_stack": load_stack(graph_path)})
return result.steps[-1].data  # summary

Task: grafosa_change_gate

{
  "name": "grafosa_change_gate",
  "taskReferenceName": "gate",
  "type": "SIMPLE",
  "inputParameters": {
    "graph_path": "${build.output.graph_path}",
    "changed_files": "${pr.changed_files}"
  }
}

Conductor worker calls:

from grafosa.pipeline import build_change_pipeline, PipelineConfig

cfg = PipelineConfig.load(".grafosa.yaml")
runner = build_change_pipeline(cfg)
result = runner.run({
    "code_stack": load_stack(graph_path),
    "changed_files": changed_files,
})
impact = result.steps[1].data  # impact step
if impact["impact_metrics"]["total_blast_radius"] > cfg.get("strategy.risk_levels.critical.radius"):
    return {"status": "FAILED", "reason": "blast radius too high"}
return {"status": "COMPLETED", "summary": result.steps[-1].data}

Task: grafosa_features (for learning pipeline)

{
  "name": "grafosa_features",
  "taskReferenceName": "features",
  "type": "SIMPLE",
  "inputParameters": {
    "graph_path": "${build.output.graph_path}",
    "entity_type": "file"
  }
}

Returns dict-of-dicts directly convertible to DataFrame:

features = result["features"]["file"]
# {"symposium/conductor.py": {"lines_of_code": 2847, "pagerank": 0.042, ...}, ...}
import pandas as pd
df = pd.DataFrame.from_dict(features, orient="index")
# → AutoML-ready DataFrame with 23 features per file

The Learning Pipeline Loop

This is the key architectural insight: *the pipeline framework creates a
feedback loop between GraFOSa's structural analysis and the learning pipeline
*.

                     .grafosa.yaml [pipelines]
                            ^
                            | (4) write updated thresholds
                            |
    GraFOSa Graph ──(1)──> Pipeline Steps ──(2)──> Feature Vectors
                                                         |
                                                    (3) AutoML
                                                         |
                                                   Learned Thresholds
                                                   (z_score, weights,
                                                    risk levels)

1. GraFOSa builds the graph from source code
2. Pipeline steps extract features (23 per file, 4 per service, 3 per symbol)
3. Learning pipeline trains on features → produces tuned thresholds
4. Thresholds written back to .grafosa.yaml → next analysis uses learned values

What the learning pipeline can tune:

What stays fixed (graph structure):

MCP Tools (for Claude Code agents)

Two new tools available when the MCP server is running:

ToolArgsReturns
run_pipeline(pipeline, changed_files)"analysis" or "change", comma-separated pathsStep results + summary JSON
extract_features(entity_type)"file", "service", or "symbol"Feature vectors (first 20)

CLI Commands

# Run analysis pipeline (no changed files)
PYTHONPATH=src python3 -m grafosa --graph examples/maestro_platform_full.json pipeline --type analysis

# Run change pipeline for specific files
PYTHONPATH=src python3 -m grafosa --graph examples/maestro_platform_full.json pipeline --type change \
  --changed symposium/src/symposium/conductor.py

# Extract file features (AutoML-ready)
PYTHONPATH=src python3 -m grafosa --graph examples/maestro_platform_full.json features --entity-type file

# Extract service features
PYTHONPATH=src python3 -m grafosa --graph examples/maestro_platform_full.json features --entity-type service

Feature Vector Schema

Per-File (23 features)

FeatureTypeDescription
lines_of_codeintTotal LOC
import_countintOutgoing IMPORTS edges
symbol_countintSymbols defined (functions, classes, etc.)
pagerankfloatGraph centrality (importance)
in_degreeintFiles that import this file
todo_countintTODO/FIXME markers
bare_except_countintexcept: pass anti-patterns
security_smell_countintSecurity issues (from semgrep)
dead_symbol_countintUnreachable symbols in this file
in_cycleboolPart of an import cycle
is_bottleneckboolIn top-10 by PageRank
has_testsbool"test" in file path
has_endpointsboolDefines HTTP endpoints
servicestrParent service name
languagestrpython or typescript
categorystrFile category

Per-Service (4 features)

FeatureTypeDescription
file_countintFiles in this service
endpoint_countintHTTP endpoints exposed
coupling_inintInbound dependency edges
coupling_outintOutbound dependency edges

Per-Symbol (3 features)

FeatureTypeDescription
caller_countintFunctions that call this one
call_countintFunctions this one calls
is_deadboolNo callers and not an endpoint handler

Backward Compatibility

All changes are backward-compatible:

hardcoded constants


What's Next

The pipeline framework is the foundation. The next steps are:

1. Conductor workers — Wrap build_analysis_pipeline() and
build_change_pipeline() as Conductor SIMPLE task workers

2. Learning pipeline integration — Feed extract_features() output into
the learning pipeline as training data; write learned thresholds back to
.grafosa.yaml

3. Custom pipeline steps — Add domain-specific steps (e.g., security
scoring, compliance checking) by implementing the Step contract

4. Remote execution — The runner's Step contract (fn(dict, config) → dict)
is designed to map directly to Conductor's inputParameters → outputParameters.
When Conductor support is added, steps can run as distributed tasks with
no contract changes.

Continue exploring