#!/usr/bin/env python3 """ H.14.3.3: Promote research artifacts from staging to permanent locations.
Per ADR-207 promotion rules:
- ALWAYS promote: executive-summaries
- CONDITIONALLY promote: SDDs, TDDs, C4 diagrams, glossaries, quick-starts, ADRs, dashboards
- NEVER promote: raw inputs, pipeline logs
Usage: python3 scripts/promote-research-artifacts.py [--dry-run] """
import os import sys import shutil import yaml from pathlib import Path from datetime import date
Paths
CORE_ROOT = Path(file).resolve().parent.parent STAGING = CORE_ROOT / "analyze-new-artifacts" MANIFESTS = CORE_ROOT / "internal" / "research" / "manifests"
Promotion targets
TARGETS = { "executive-summary": CORE_ROOT / "internal" / "research" / "executive-summaries", "sdd": CORE_ROOT / "internal" / "architecture" / "sdd", "tdd": CORE_ROOT / "internal" / "architecture" / "tdd", "c4-diagram": CORE_ROOT / "internal" / "architecture" / "c4-models", "glossary": CORE_ROOT / "internal" / "research" / "glossaries", "quick-start": CORE_ROOT / "internal" / "research" / "quick-start-guides", "dashboard": CORE_ROOT / "internal" / "dashboards" / "research", }
Map of staging dirs -> artifact files to promote
Format: {dir_name: [(source_file, artifact_type, promoted_name), ...]}
PROMOTIONS = { "CODITECT-palantir-research": [ ("01-executive-summary.md", "executive-summary", "palantir-research-executive-summary.md"), ("02-quick-start-guide.md", "quick-start", "palantir-research-quick-start.md"), ("04-sdd.md", "sdd", "palantir-aip-integration-sdd.md"), ("05-tdd.md", "tdd", "palantir-aip-integration-tdd.md"), ("07-glossary.md", "glossary", "palantir-research-glossary.md"), ("03-coditect-impact.md", "executive-summary", "palantir-coditect-impact.md"), ("coditect-strategy-visualizer.jsx", "dashboard", "palantir-strategy-visualizer.jsx"), ("palantir-financial-dashboard.jsx", "dashboard", "palantir-financial-dashboard.jsx"), ("rule-of-40-dashboard.jsx", "dashboard", "palantir-rule-of-40-dashboard.jsx"), ], "coditect-gemini-api-context-url": [ ("01-Executive-Summary-Gemini-URL-Context-Coditect-Impact.md", "executive-summary", "gemini-url-context-executive-summary.md"), ("03-SDD-Coditect-Web-Intelligence-Layer.md", "sdd", "gemini-web-intelligence-layer-sdd.md"), ("04-TDD-Gemini-URL-Context-Integration.md", "tdd", "gemini-url-context-integration-tdd.md"), ], "CODITECT-consequence-aware-automous-execution": [ ("01-executive-summary.md", "executive-summary", "consequence-aware-execution-executive-summary.md"), ("06-consequence-aware-architecture.md", "sdd", "consequence-aware-architecture-sdd.md"), ], "coditect-bioscience-workorders-research": [ ("01-executive-summary.md", "executive-summary", "bioscience-workorders-executive-summary.md"), ("12-sdd.md", "sdd", "bioscience-workorders-sdd.md"), ("13-tdd.md", "tdd", "bioscience-workorders-tdd.md"), ("14-c4-architecture.md", "c4-diagram", "bioscience-workorders-c4-architecture.md"), ("27-coditect-impact.md", "executive-summary", "bioscience-workorders-coditect-impact.md"), ], "coditect-avivatect-fp-and-a-research": [ ("01-EXECUTIVE-ANALYSIS.md", "executive-summary", "avivatec-fpa-executive-analysis.md"), ("C4-ARC-001-architecture-diagrams.md", "c4-diagram", "avivatec-fpa-c4-architecture.md"), ("10-CODITECT-IMPACT.md", "executive-summary", "avivatec-fpa-coditect-impact.md"), ], "coditect-value-proposition": [ ("coditect-executive-one-pager.md", "executive-summary", "value-proposition-executive-one-pager.md"), ("coditect-impact-analysis.md", "executive-summary", "value-proposition-impact-analysis.md"), ("coditect-gtm-strategy-enterprise-agentic.md", "executive-summary", "value-proposition-gtm-strategy.md"), ("coditect-value-prop-hero.jsx", "dashboard", "value-proposition-hero.jsx"), ("coditect-pricing-tiers.jsx", "dashboard", "value-proposition-pricing-tiers.jsx"), ("coditect-competitive-positioning.jsx", "dashboard", "value-proposition-competitive-positioning.jsx"), ], "coditect-prompt-repetition-research": [ ("01_executive_summary_prompt_repetition.md", "executive-summary", "prompt-repetition-executive-summary.md"), ("02_technical_implementation_guide.md", "sdd", "prompt-repetition-technical-implementation.md"), ("03_business_case_roi_analysis.md", "executive-summary", "prompt-repetition-business-case.md"), ], "coditect-recursive-large-language-models": [ ("01_RLM_Executive_Summary.md", "executive-summary", "recursive-llm-executive-summary.md"), ("02_RLM_Technical_Implementation.md", "sdd", "recursive-llm-technical-implementation.md"), ], # coditect-master-prompt-research is DUPLICATE of gemini-api — skip "coditect-agentic-paradigms-for-llm\u2011enabled-healthcare-communication": [ ("01-executive-summary.md", "executive-summary", "healthcare-agentic-paradigms-executive-summary.md"), ("04-coditect-impact-analysis.md", "executive-summary", "healthcare-agentic-paradigms-coditect-impact.md"), ("07-paradigm-taxonomy-visual.jsx", "dashboard", "healthcare-paradigm-taxonomy.jsx"), ], }
def promote_artifacts(dry_run=False): """Promote artifacts from staging to permanent locations.""" promoted = 0 skipped = 0 errors = 0 manifest_updates = {} # {manifest_file: [(artifact_type, promoted_path)]}
for dir_name, artifacts in PROMOTIONS.items():
staging_dir = STAGING / dir_name
if not staging_dir.exists():
print(f"SKIP: {dir_name} - staging dir not found")
skipped += len(artifacts)
continue
for source_file, artifact_type, promoted_name in artifacts:
source = staging_dir / source_file
if not source.exists():
print(f" SKIP: {source_file} - not found in {dir_name}")
skipped += 1
continue
target_dir = TARGETS.get(artifact_type)
if not target_dir:
print(f" SKIP: {source_file} - no target for type '{artifact_type}'")
skipped += 1
continue
target = target_dir / promoted_name
if target.exists():
print(f" EXISTS: {promoted_name} - already promoted")
skipped += 1
continue
if dry_run:
print(f" DRY-RUN: {source_file} -> {target.relative_to(CORE_ROOT)}")
promoted += 1
else:
try:
shutil.copy2(str(source), str(target))
rel_target = str(target.relative_to(CORE_ROOT))
print(f" OK: {source_file} -> {rel_target}")
promoted += 1
# Track manifest updates
# Find matching manifest
topic = dir_name.lower().replace("coditect-", "").replace("coditect_", "")
if dir_name not in manifest_updates:
manifest_updates[dir_name] = []
manifest_updates[dir_name].append((artifact_type, rel_target, source_file))
except Exception as e:
print(f" ERROR: {source_file} - {e}")
errors += 1
print(f"\n{'='*60}")
print(f"Promoted: {promoted}")
print(f"Skipped: {skipped}")
print(f"Errors: {errors}")
# Update manifests
if not dry_run and manifest_updates:
print(f"\nUpdating {len(manifest_updates)} manifests...")
update_manifests(manifest_updates)
return promoted, skipped, errors
def update_manifests(manifest_updates): """Update YAML manifests with promoted_to paths.""" today = date.today().isoformat()
for dir_name, promotions in manifest_updates.items():
# Find the manifest file
topic = dir_name.lower()
for prefix in ["coditect-", "coditect_"]:
topic = topic.replace(prefix, "")
# Search for matching manifest
manifest_file = None
for f in MANIFESTS.glob("*.yaml"):
if topic.replace("-", "") in f.stem.replace("-", ""):
manifest_file = f
break
if not manifest_file:
# Try broader match
words = topic.split("-")[:3]
for f in MANIFESTS.glob("*.yaml"):
if all(w in f.stem for w in words if len(w) > 3):
manifest_file = f
break
if not manifest_file:
print(f" WARN: No manifest found for {dir_name}")
continue
try:
content = manifest_file.read_text()
lines = content.split("\n")
# Add promoted artifact entries
new_lines = []
for line in lines:
new_lines.append(line)
# Append promoted artifacts before tags section
insert_idx = len(new_lines)
for i, line in enumerate(new_lines):
if line.startswith("tags:"):
insert_idx = i
break
promoted_entries = []
for artifact_type, promoted_path, source_file in promotions:
promoted_entries.append(f" - type: {artifact_type}")
promoted_entries.append(f" staging_path: \"{source_file}\"")
promoted_entries.append(f" promoted_to: \"{promoted_path}\"")
promoted_entries.append(f" status: promoted")
promoted_entries.append(f" promotion_date: {today}")
# Insert before tags
for entry in reversed(promoted_entries):
new_lines.insert(insert_idx, entry)
manifest_file.write_text("\n".join(new_lines))
print(f" OK: Updated {manifest_file.name} with {len(promotions)} promotions")
except Exception as e:
print(f" ERROR: Failed to update manifest for {dir_name}: {e}")
if name == "main": dry_run = "--dry-run" in sys.argv if dry_run: print("=== DRY RUN MODE ===\n") print(f"Promoting artifacts from {STAGING}") print(f"To permanent locations under {CORE_ROOT / 'internal'}\n") promote_artifacts(dry_run)