brand-gen-phase-contract-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited brand-gen-phase-contract-audit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
For Sage brand work in Pi, use the paste-ready prompt at docs/prompts/pi-sage-brand-gen-full-pipeline.md. Keep this link instead of copying the full prompt into skill bodies.
Risk addressed: the in-process contract between pipeline phases is argparse.Namespace. There are 426 `getattr(args, ...)` call sites across 16 modules. PipelineRequest.build_scratchpad_namespace (pipeline_request.py:332) hand-builds a Namespace with ~30 fields just to pass typed data between in-process stages. getattr(args, "field", None) swallows typos, so renames silently zero out values. New fields require parallel updates in PIPELINE_MCP_PROPERTIES, PipelineRequest, from_mapping, build_scratchpad_namespace, the CLI builder, and per-phase getattr calls. Tests pass argparse.Namespace() so phantom fields slip through.
PlanDraft and GenerationScratchpad dataclasses exist but _run_scratchpad operates on the dict payload and converts at the end via scratchpad_from_dict. The _filter_fields helper (pipeline_types.py:386) silently drops unknown keys.
{
"summary": {
"total_getattr_sites": 426,
"phantom_fields": 17,
"phases_with_drift": 4,
"fields_declared_but_unused": 8,
"namespace_fields_total": 73,
"typed_request_fields_total": 41
},
"phases": [
{
"phase": "route",
"consumed_fields": ["route_brief", "material_type", "render_backend", ...],
"declared_in": ["PipelineRequest"],
"phantom_in_phase": [],
"untyped_via_namespace_only": ["route_force"]
},
{
"phase": "plan",
"consumed_fields": [...],
"declared_in": ["MaterialPlan", "PipelineRequest"],
"phantom_in_phase": ["legacy_inspiration_seed"],
"untyped_via_namespace_only": ["accept_inspiration_recommendations"]
}
/* ... per-phase ... */
],
"phantom_fields_detail": [
{
"field": "legacy_inspiration_seed",
"read_at": ["plan_builder.py:412"],
"never_written_at": "no PipelineRequest entry, no Namespace builder line",
"default_returned": "None",
"blast_radius": "silent — production has never set this; renames break nothing but the field is dead"
}
],
"filter_fields_drift": [
{
"field": "branch_id",
"declared_in": "MaterialPlan, GenerationScratchpad",
"missing_from": "scratchpad_from_dict input shape",
"behavior": "silently dropped at deserialization"
}
],
"duplicate_field_routing": [
{
"field": "design_variance",
"paths": ["PipelineRequest.design_variance", "Namespace.design_variance", "scratchpad payload.design_variance"],
"consistency": "ok"
}
]
}bgen orchestrate-material — to know how many sites need a parallel update._filter_fields drops a field you expected to survive.pipeline_runner._scratchpad_args (pipeline_runner.py:806).$PWD).--phase <name> — restrict audit to one phase. Otherwise audits all six.brand_gen/pipeline_types.py and brand_gen/pipeline_request.py. Capture every dataclass field name from PipelineRequest, RoutingBrief, PlanDraft, MaterialPlan, GenerationScratchpad, PipelineResult, plus any nested types. Build a set keyed by (class, field_name).PipelineRequest.build_scratchpad_namespace (pipeline_request.py:332) and pipeline_runner._scratchpad_args (pipeline_runner.py:806). Capture every attribute set on argparse.Namespace. These are "fields the pipeline says exist."brand_gen/ for getattr(args, "([^"]+)". Group results by enclosing function/file. Tag each function with its phase using these mappings:_run_route / route_brief / classify_workflow_route_smart → routecreate_material_plan / _run_plan / plan_builder.py functions → planvalidate_* / _run_critique → validateassemble_generation_scratchpad / execute_generation_scratchpad / _run_scratchpad / _run_generate → executeapply_generation_critique_policy / vlm_critique / auto_capture_* → reviewevolve_* / promote_* → evolvegetattr(args, X), check whether X is in the typed-field universe AND in the Namespace-field universe. A phantom is a field consumed via getattr but absent from BOTH writers and ALL declared dataclasses. Mark these with their default-fallback so the user knows whether the silent-zero behavior matters.getattr(args, field) references it. Fields declared but never read are dead.pipeline_types.py:386 (_filter_fields) and every caller of from_dict (scratchpad_from_dict, plan_from_dict, etc.). For each typed dataclass, check whether the from_dict reconciliation walks the same field set as the dataclass declares. Catch nested-key fallbacks (pipeline_types.py:445-451)._filter_fields ranks high for any persisted field. Dead declarations are low-priority.See "What this skill produces" above. Also emit a per-phase markdown table for human review:
| Phase | Consumed | Typed | Phantom | Drift |
|-------|----------|-------|---------|-------|
| plan | 47 | 41 | 3 | 1 |brand_gen/pipeline_request.py:332 — build_scratchpad_namespace (the Namespace contract).brand_gen/pipeline_runner.py:806 — _scratchpad_args (the second Namespace builder).brand_gen/pipeline_types.py:386, 445-451 — _filter_fields and nested fallback reconciliation.brand_gen/cli_builders.py — CLI args that flow into the Namespace.brand_gen/commands/generation.py — wires CLI to the runner.brand_iterate_mcp.py: schema, Namespace, constructor." — verify the audit catches drift across these three sites.compound-engineering:ce-plan design the migration to typed phase IO.getattr(obj, ...) is used elsewhere in the codebase. Filter to getattr(args, ...) and to functions tagged with a pipeline phase.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.