diff --git a/data/verisim/recipes/recipe-fix-pmpl-drift.json b/data/verisim/recipes/recipe-fix-pmpl-drift.json new file mode 100644 index 00000000..ec9b321e --- /dev/null +++ b/data/verisim/recipes/recipe-fix-pmpl-drift.json @@ -0,0 +1,68 @@ +{ + "id": "recipe-fix-pmpl-drift", + "triangle_tier": "eliminate", + "pattern_ids": ["PA-license-pmpl_drift"], + "description": "Flip legacy PMPL-1.0-or-later SPDX stamps to the repo's per-category target (MPL-2.0 for sole-owner, AGPL-3.0-or-later for son-shared) per the 2026-06-02 owner directive. Skips palimpsest carve-out repos and third-party content.", + "confidence": 0.95, + "languages": ["*"], + "auto_fixable": true, + "fix_script": "fix-pmpl-drift.sh", + "policy_reference": "2026-06-02 estate-license-policy-umbrella directive (jonathan.jewell@gmail.com)", + "category_classification": { + "sole_owner_default": { + "target": "MPL-2.0", + "detection": "LICENSE file SPDX-License-Identifier: MPL-2.0" + }, + "son_shared": { + "target": "AGPL-3.0-or-later", + "detection": "LICENSE file SPDX-License-Identifier: AGPL-3.0-or-later", + "confirmed_repos": ["idaptik", "burble", "standards", "rattlescript", "vcl-ut"] + }, + "all_rights_reserved": { + "target": "DO NOT TOUCH", + "confirmed_repos": ["007"] + }, + "palimpsest_carve_out": { + "target": "DO NOT FLIP (keep PMPL-1.0-or-later)", + "confirmed_repos": ["palimpsest-license", "palimpsest-plasma"], + "prospective_special_case": { + "repo": "consent-aware-http", + "current_location": "subdir at hyperpolymath/standards/consent-aware-http/", + "license_design": "MPL-2.0 source + CC-BY-4.0 spec + PMPL-2.0-or-later referenced", + "see_memory": "feedback_consent_aware_http_hybrid_licensing.md" + } + }, + "third_party_or_forks": { + "target": "DO NOT TOUCH", + "rule": "Never sweep upstream-tracked content" + } + }, + "exclude_repos": [ + "007", + "palimpsest-license", + "palimpsest-plasma", + "game-server-admin", + "airborne-submarine-squadron", + "paint-type" + ], + "exclude_subpaths": [ + "rescript-tea/", + "rescript-vite/", + "affinescript-vite/", + "idaptik-rescript13-staging/", + "consent-aware-http/" + ], + "first_landed": "2026-06-02", + "initial_sweep_prs": { + "neurophone#102": "canonical reference (138 files)", + "developer-ecosystem#103/104/105/106": "phased per-subdir (7033 files)", + "nextgen-databases#29/30": "phased per-subdir (226 files)", + "standards#344/345": "phased AGPL target (3417 files)", + "stapeln#86/87": "phased per-subdir (875 files)", + "reposystem#90": "Phase 1 (401 files)", + "ephapax#285": "single (343 files)", + "sanctify-php#47, ubicity#73, zerotier-k8s-link#63, verisimiser#156, squisher-corpus#26, rattlescript#29, pimcore-fortress#22, tree-navigator#41, snapcreate#29, php-aegis#43, nafa-app#26, vscode-k9#22, supernorma#38, sdp-hkdf-deployment#26, robot-vacuum-cleaner#64, gitbot-fleet#250, vcl-ut#46, resource-record-fluctuator#38, proof-of-work#83, project-wharf#49, julia-professional-registry#25": "single-PR sweeps" + }, + "successful_fixes": 0, + "failed_fixes": 0 +} diff --git a/data/verisim/recipes/recipe-fix-spdx-license.json b/data/verisim/recipes/recipe-fix-spdx-license.json index d5eea8d3..195f6676 100644 --- a/data/verisim/recipes/recipe-fix-spdx-license.json +++ b/data/verisim/recipes/recipe-fix-spdx-license.json @@ -7,7 +7,7 @@ "languages": ["*"], "auto_fixable": true, "fix_script": "fix-missing-spdx.sh", - "exclude_repos": ["game-server-admin", "idaptik", "airborne-submarine-squadron"], + "exclude_repos": ["007", "game-server-admin", "idaptik", "burble", "standards", "rattlescript", "vcl-ut", "airborne-submarine-squadron", "palimpsest-license", "palimpsest-plasma", "paint-type"], "successful_fixes": 7457, "failed_fixes": 0 } diff --git a/scripts/fix-scripts/fix-pmpl-drift.sh b/scripts/fix-scripts/fix-pmpl-drift.sh new file mode 100755 index 00000000..2bbea18c --- /dev/null +++ b/scripts/fix-scripts/fix-pmpl-drift.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# fix-pmpl-drift.sh — Flip legacy PMPL-1.0-or-later SPDX stamps to repo-category target +# Recipe: recipe-fix-pmpl-drift (confidence: 0.95, auto_fixable: true) +# +# Per 2026-06-02 owner directive: +# sole-owner default → MPL-2.0 +# son-shared → AGPL-3.0-or-later (confirmed: idaptik, burble, standards, rattlescript, vcl-ut) +# palimpsest carve-out → KEEP PMPL (palimpsest-license, palimpsest-plasma; consent-aware-http special) +# 007 → DO NOT TOUCH (ARR) +# third-party/forks → DO NOT TOUCH +# +# Usage: fix-pmpl-drift.sh [--dry-run] [--file ] + +set -euo pipefail + +REPO_PATH="${1:?Usage: fix-pmpl-drift.sh [--dry-run]}" +DRY_RUN="" +SPECIFIC_FILE="" + +shift +while [ $# -gt 0 ]; do + case "$1" in + --dry-run) DRY_RUN=1 ;; + --file) SPECIFIC_FILE="$2"; shift ;; + *) echo "Unknown arg: $1" >&2; exit 1 ;; + esac + shift +done + +REPO_NAME=$(basename "$REPO_PATH") + +# ─── Carve-out check ─── +SKIP_REPOS=( + "007" + "palimpsest-license" + "palimpsest-plasma" + "game-server-admin" + "airborne-submarine-squadron" + "paint-type" +) +for skip in "${SKIP_REPOS[@]}"; do + if [ "$REPO_NAME" = "$skip" ]; then + echo "SKIP: $REPO_NAME is on the exclude_repos list (carve-out or third-party)" + exit 0 + fi +done + +# ─── Category classification via LICENSE file ─── +LICENSE_PATH="$REPO_PATH/LICENSE" +if [ ! -f "$LICENSE_PATH" ]; then + echo "WARN: no LICENSE file at $LICENSE_PATH — skipping (cannot classify)" + exit 0 +fi + +LIC_HEAD=$(head -1 "$LICENSE_PATH" | tr -d '\n') + +if echo "$LIC_HEAD" | grep -q "MPL-2.0"; then + TARGET="MPL-2.0" + CATEGORY="sole-owner" +elif echo "$LIC_HEAD" | grep -q "AGPL-3.0"; then + TARGET="AGPL-3.0-or-later" + CATEGORY="son-shared" +elif echo "$LIC_HEAD" | grep -q "PMPL-1.0-or-later"; then + echo "INFO: $REPO_NAME LICENSE is PMPL-1.0-or-later (carve-out or staging) — skipping" + exit 0 +else + echo "WARN: $REPO_NAME LICENSE is unfamiliar (\"$LIC_HEAD\") — skipping (manual review)" + exit 0 +fi + +# ─── Sub-path exclusions ─── +EXCLUDE_PATTERNS=( + "/.git/" + "/LICENSES/" + "/rescript-tea/" + "/rescript-vite/" + "/affinescript-vite/" + "/idaptik-rescript13-staging/" + "/consent-aware-http/" +) +GREP_EXCLUDE="" +for p in "${EXCLUDE_PATTERNS[@]}"; do + GREP_EXCLUDE+="${GREP_EXCLUDE:+|}$p" +done + +# ─── Submodule exclusion (skip submodule paths) ─── +SUB_PATHS="" +if [ -f "$REPO_PATH/.gitmodules" ]; then + while IFS= read -r submodule_path; do + SUB_PATHS+="${SUB_PATHS:+|}${submodule_path}/" + done < <(grep "path =" "$REPO_PATH/.gitmodules" | awk '{print $3}') +fi +[ -n "$SUB_PATHS" ] && GREP_EXCLUDE="$GREP_EXCLUDE|$SUB_PATHS" + +# ─── Find drift files ─── +cd "$REPO_PATH" +if [ -n "$SPECIFIC_FILE" ]; then + FILES="$SPECIFIC_FILE" +else + FILES=$(grep -rl "SPDX-License-Identifier: PMPL-1.0-or-later" . 2>/dev/null | grep -vE "$GREP_EXCLUDE" || true) +fi + +COUNT=$(echo "$FILES" | grep -c . 2>/dev/null || echo 0) + +if [ "$COUNT" -eq 0 ]; then + echo "OK: $REPO_NAME has no PMPL drift in safe scope" + exit 0 +fi + +echo "$REPO_NAME ($CATEGORY → $TARGET): $COUNT files with PMPL drift" + +if [ -n "$DRY_RUN" ]; then + echo "$FILES" | head -20 + [ "$COUNT" -gt 20 ] && echo "... and $((COUNT - 20)) more" + exit 0 +fi + +# ─── Flip ─── +echo "$FILES" | xargs sed -i "s|SPDX-License-Identifier: PMPL-1.0-or-later|SPDX-License-Identifier: $TARGET|g" + +REMAINING=$(grep -rl "SPDX-License-Identifier: PMPL-1.0-or-later" . 2>/dev/null | grep -vE "$GREP_EXCLUDE" | wc -l) +echo "Flipped $COUNT files. Remaining PMPL in scope: $REMAINING."