killinchu / .github /workflows /hf-sync.yml
betterwithage's picture
SAPA: Energy-per-Successful-Goal accounting layer (ADDITIVE, doctrine-honest)
f017b75 verified
Raw
History Blame
18.2 kB
name: Sync to HuggingFace Space
# hf-sync: keep the HuggingFace Space in lockstep with canonical GitHub main on
# szl-holdings/killinchu, split into two INDEPENDENT concerns that each trigger
# only on their own changes:
#
# * README sync (sync-readme job) — fires on README.md (or this workflow)
# pushes. Pushes the Space card (README.md) VERBATIM, byte-for-byte. The
# GitHub README already carries the full HF Space front-matter (enforced by
# readme-frontmatter-check.yml), so no front-matter strip/re-inject. A
# SAFETY GUARD refuses a blind push that would sharply shrink the card
# (new < old * MIN_RATIO); override an intentional reduction via
# workflow_dispatch force=true.
#
# * App-file mirror (mirror-app job) — fires ONLY on pushes that touch the
# deployed app files listed in the APP_FILES env below (serve.py, Dockerfile,
# and the route modules). A README-only push no longer re-pushes app code or
# forces a no-op Space commit. After mirroring, this job triggers a
# HuggingFace factory rebuild via the HF API so the new code actually goes
# live with no manual step. Idempotent: identical content is a no-op.
#
# A lightweight detect job computes which file groups changed (git diff, no
# third-party actions — org policy allows only github-owned/verified actions)
# and gates the two jobs. workflow_dispatch runs both.
#
# SINGLE SOURCE OF TRUTH for the mirrored app files: the workflow-level
# `env.APP_FILES` below. Both the detect gate and the mirror-app job read it, so
# adding/removing a mirrored route module is a one-word change there. GitHub
# requires `on.push.paths` to be a LITERAL list (it cannot reference env/vars),
# so the trigger list must be kept in lockstep with APP_FILES BY HAND — adding a
# route module = one line in on.push.paths + one word in APP_FILES.
#
# Credential: HF_WRITE_TOKEN (HuggingFace write token with org-write to
# SZLHOLDINGS). The legacy HF_TOKEN secret is retired.
on:
push:
branches: [main]
paths:
- "README.md"
- ".github/workflows/hf-sync.yml"
# ---- app files: KEEP IDENTICAL to env.APP_FILES below (hf-sync-paths-guard enforces). ----
- "serve.py"
- "Dockerfile"
- "operator_shell_v4.py"
- "szl_evidence_research.py"
- "szl_readiness.py"
- "szl_quantum_bio.py"
- "szl_unified_formulas.py"
- "szl_cuas_formulas.py"
- "killinchu_research_sources.py"
- "szl_contracting.py"
- "szl_conjecture_factory.py"
- "killinchu_backend.py"
- "a11oy_hf_assets.py"
- "killinchu_protocols.py"
- "killinchu_expansion.py"
- "killinchu_naval_haps.py"
- "szl_dsse.py"
- "szl_provenance.py"
- "szl_live_wires.py"
- "szl_rosie_companion.py"
- "killinchu_szl_pqc_sign.py"
- "szl_rekor.py"
- "killinchu_osint.py"
- "szl_be_hardening.py"
- "szl_unay.py"
- "szl_khipu_lmdb.py"
- "szl_khipu_replicate.py"
- "szl_unay_routes.py"
- "szl_warhacker_aliases.py"
- "killinchu_genius.py"
- "killinchu_warhacker_demos.py"
- "killinchu_v3.py"
- "szl_brain.py"
- "szl_rag.py"
- "szl_formulas.py"
- "szl_understudy.py"
- "szl_killinchu_cookbook.py"
- "szl_uds_hardening.py"
- "killinchu_fusion.py"
- "szl_v4_fleet.py"
- "szl_ken.py"
- "killinchu_frontier_patch.py"
- "killinchu_drone_routes.py"
- "killinchu_parity.py"
- "killinchu_cannonico.py"
- "killinchu_elite_console.py"
- "_vendor_blobs.py"
- "killinchu_fleet_vessels.py"
- "killinchu_maritime_risk.py"
- "killinchu_maritime_intel.py"
- "killinchu_maritime_view.py"
- "killinchu_live_feeds.py"
- "killinchu_feeds_realdata.py"
- "killinchu_asw.py"
- "killinchu_anatomy.py"
- "killinchu_health_twin.py"
- "killinchu_beyond.py"
- "szl_khipu_consensus.py"
- "killinchu_mesh.py"
- "killinchu_mesh_view.py"
- "killinchu_formula_endpoints.py"
- "killinchu_edge_formulas.py"
- "killinchu_active_flux.py"
- "killinchu_platform_dynamics.py"
- "killinchu_edge_console.py"
- "szl_agentic_loop.py"
- "szl_anatomy_routes.py"
- "szl_formula_wiring.py"
- "a11oy_code_engine.py"
- "killinchu_ops_control.py"
- "szl_llm_registry.py"
- "szl_alloy_models.py"
- "a11oy_agent_loop.py"
- "a11oy_org_rag.py"
- "a11oy_mcp_client.py"
- "killinchu_mined_ops.py"
- "killinchu_resweep_ops.py"
- "killinchu_wave910.py"
- "killinchu_posture_topology.py"
- "szl_connectors_serve.py"
- "szl_connector_mcp.py"
- "szl_scaling.py"
- "szl_allodial.py"
- "szl_entanglement.py"
- "szl_neuroplasticity.py"
- "szl_chain_of_title.py"
- "killinchu_mosaic.py"
- "szl_mosaic_core.py"
- "killinchu_autonomy.py"
- "killinchu_autonomy_view.py"
- "killinchu_organism.py"
- "killinchu_organism_view.py"
- "szl_energy_sovereign.py"
- "szl_joules_truth.py"
# SAPA: Energy per Successful Goal — the frontier agentic unit on top of the live
# MEASURED joules/token path. szl_sapa.py is the shared accounting layer (byte-
# identical a11oy<->killinchu); szl_sapa_patch.py front-inserts /sapa +
# /api/killinchu/v1/sapa/*. KEEP IDENTICAL to env.APP_FILES below (paths-guard enforces).
- "szl_sapa.py"
- "szl_sapa_patch.py"
- "szl_kc_tda_fracture.py"
- "a11oy_autoreview.py"
- "szl_conformal.py"
- "szl_calibration.py"
- "szl_hf_bucket.py"
- "szl_metrics_prom.py"
- "killinchu_maritime_globe.py"
- "killinchu_elite_wiring.py"
- "killinchu_flow_compartments.py"
- "szl_codename_gate.py"
- "szl_ecosystem_routes.py"
- "szl_restraint.py"
- "killinchu_restraint_tile.py"
workflow_dispatch:
inputs:
force:
description: "Bypass the anti-shrink guard for an intentional large README reduction"
type: boolean
default: false
permissions:
contents: read
env:
# SINGLE SOURCE OF TRUTH for the mirrored app files (space-separated). The
# detect gate and the mirror-app job both read this. Adding a route module is a
# one-word change here (plus the matching literal line in on.push.paths above).
APP_FILES: "serve.py Dockerfile operator_shell_v4.py szl_evidence_research.py szl_readiness.py szl_quantum_bio.py szl_unified_formulas.py szl_cuas_formulas.py killinchu_research_sources.py szl_contracting.py szl_conjecture_factory.py killinchu_backend.py a11oy_hf_assets.py killinchu_protocols.py killinchu_expansion.py killinchu_naval_haps.py szl_dsse.py szl_provenance.py szl_live_wires.py szl_rosie_companion.py killinchu_szl_pqc_sign.py szl_rekor.py killinchu_osint.py szl_be_hardening.py szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py szl_warhacker_aliases.py killinchu_genius.py killinchu_warhacker_demos.py killinchu_v3.py szl_brain.py szl_rag.py szl_formulas.py szl_understudy.py szl_killinchu_cookbook.py szl_uds_hardening.py killinchu_fusion.py szl_v4_fleet.py szl_ken.py killinchu_frontier_patch.py killinchu_drone_routes.py killinchu_parity.py killinchu_cannonico.py killinchu_elite_console.py _vendor_blobs.py killinchu_fleet_vessels.py killinchu_maritime_risk.py killinchu_maritime_intel.py killinchu_maritime_view.py killinchu_live_feeds.py killinchu_feeds_realdata.py killinchu_asw.py killinchu_anatomy.py killinchu_health_twin.py killinchu_beyond.py szl_khipu_consensus.py killinchu_mesh.py killinchu_mesh_view.py killinchu_formula_endpoints.py killinchu_edge_formulas.py killinchu_active_flux.py killinchu_platform_dynamics.py killinchu_edge_console.py szl_agentic_loop.py szl_anatomy_routes.py szl_formula_wiring.py a11oy_code_engine.py killinchu_ops_control.py szl_llm_registry.py szl_alloy_models.py a11oy_agent_loop.py a11oy_org_rag.py a11oy_mcp_client.py killinchu_mined_ops.py killinchu_resweep_ops.py killinchu_wave910.py killinchu_posture_topology.py szl_connectors_serve.py szl_connector_mcp.py szl_scaling.py szl_allodial.py szl_entanglement.py szl_neuroplasticity.py szl_chain_of_title.py killinchu_mosaic.py szl_mosaic_core.py killinchu_autonomy.py killinchu_autonomy_view.py killinchu_organism.py killinchu_organism_view.py szl_energy_sovereign.py szl_joules_truth.py szl_sapa.py szl_sapa_patch.py szl_kc_tda_fracture.py a11oy_autoreview.py szl_conformal.py szl_calibration.py szl_hf_bucket.py szl_metrics_prom.py killinchu_maritime_globe.py killinchu_elite_wiring.py killinchu_flow_compartments.py szl_codename_gate.py szl_ecosystem_routes.py szl_restraint.py killinchu_restraint_tile.py"
jobs:
detect:
runs-on: ubuntu-latest
outputs:
readme: ${{ steps.filter.outputs.readme }}
app: ${{ steps.filter.outputs.app }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
lfs: false
- name: Detect which file groups changed
id: filter
env:
EVENT: ${{ github.event_name }}
BEFORE: ${{ github.event.before }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
# A manual run cannot diff against a previous commit; run both concerns.
if [ "$EVENT" = "workflow_dispatch" ]; then
echo "readme=true" >> "$GITHUB_OUTPUT"
echo "app=true" >> "$GITHUB_OUTPUT"
echo "workflow_dispatch: running both README sync and app mirror."
exit 0
fi
base="${BEFORE:-}"
# First push to a branch (all-zero before) or a missing base commit:
# fall back to the immediate parent, then to the single-commit view.
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ] \
|| ! git cat-file -e "${base}^{commit}" 2>/dev/null; then
base="$(git rev-parse "${SHA}^" 2>/dev/null || true)"
fi
if [ -n "$base" ]; then
changed="$(git diff --name-only "$base" "$SHA")"
else
changed="$(git show --name-only --pretty=format: "$SHA")"
fi
echo "Changed files:"
echo "$changed"
readme=false
app=false
while IFS= read -r f; do
[ -z "$f" ] && continue
case "$f" in
README.md|.github/workflows/hf-sync.yml) readme=true ;;
esac
# Match against the single-source APP_FILES list (space-separated).
for af in $APP_FILES; do
[ "$f" = "$af" ] && app=true
done
done <<< "$changed"
echo "readme=$readme" >> "$GITHUB_OUTPUT"
echo "app=$app" >> "$GITHUB_OUTPUT"
echo "Decision: readme=$readme app=$app"
sync-readme:
needs: detect
if: needs.detect.outputs.readme == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 1
lfs: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Install huggingface_hub
run: pip install --quiet "huggingface_hub>=0.25"
- name: Sync README verbatim (with anti-shrink safety guard)
env:
HF_TOKEN: ${{ secrets.HF_WRITE_TOKEN }}
SPACE_ID: SZLHOLDINGS/killinchu
FORCE: ${{ inputs.force }}
MIN_RATIO: "0.85"
run: |
set -euo pipefail
if [ -z "${HF_TOKEN:-}" ]; then
echo "::error::HF_WRITE_TOKEN secret is not set — cannot push to the HuggingFace Space."
echo "::error::Founder action: add repo secret HF_WRITE_TOKEN (HF write token with org-write to SZLHOLDINGS)."
exit 1
fi
python3 <<'PYEOF'
import os, sys
from huggingface_hub import HfApi, CommitOperationAdd, hf_hub_download
# HF's server-side README YAML validator occasionally returns a non-JSON
# body (HTML/5xx) and raises, aborting an otherwise-valid commit. The
# front-matter is well-formed (it is identical to what the Space already
# serves), so make the validator non-fatal.
_orig = HfApi._validate_yaml
def _safe(self, content, *a, **k):
try:
return _orig(self, content, *a, **k)
except Exception as e:
print("::warning::HF _validate_yaml skipped (non-fatal):", repr(e)[:160])
return None
HfApi._validate_yaml = _safe
token = os.environ["HF_TOKEN"]
space = os.environ["SPACE_ID"]
force = os.environ.get("FORCE", "").lower() == "true"
min_ratio = float(os.environ.get("MIN_RATIO", "0.85"))
with open("README.md", "rb") as fh:
new = fh.read()
# Front-matter sanity: a verbatim push must still be a valid Space card.
head = new[:4096]
if not new.startswith(b"---") or b"\nsdk:" not in head:
print("::error::Incoming README is missing YAML front-matter or the 'sdk:' field; refusing to push (would break the Space).")
sys.exit(1)
api = HfApi(token=token)
# Fetch the current Space README for the anti-shrink guard.
old = b""
try:
p = hf_hub_download(repo_id=space, repo_type="space",
filename="README.md", token=token)
with open(p, "rb") as fh:
old = fh.read()
except Exception as e:
print("::warning::Could not fetch current Space README (treating as new):", repr(e)[:160])
if old and new == old:
print("Space README already byte-identical (%d bytes); nothing to push." % len(new))
sys.exit(0)
if old and not force and len(new) < len(old) * min_ratio:
print("::error title=anti-shrink guard tripped::Refusing blind push.")
print("::error::Incoming README is %d bytes vs %d on the Space (%.1f%% of current; floor is %.0f%%)."
% (len(new), len(old), 100.0 * len(new) / len(old), min_ratio * 100))
print("::error::This looks like an accidental content deletion. If the reduction is intentional, re-run with workflow_dispatch force=true.")
sys.exit(1)
commit = api.create_commit(
repo_id=space,
repo_type="space",
operations=[CommitOperationAdd(path_in_repo="README.md",
path_or_fileobj=new)],
commit_message="docs: sync Space card with GitHub README (verbatim, byte-identical)",
commit_description=("Automated README sync from szl-holdings/killinchu main via hf-sync.\n"
"Verbatim push; anti-shrink guard floor=%.2f." % min_ratio),
)
print("HF commit:", commit.oid, "->", space, "(%d bytes)" % len(new))
PYEOF
# ADDITIVE: the README-only sync above cannot make an app route live. This
# job mirrors the deployed backend from canonical GitHub main to the Space so
# the Space code never drifts behind GitHub. It runs ONLY when one of the
# env.APP_FILES changes (the detect gate above), but the set it actually
# mirrors + sweeps is the FULL backend the image is built from — every .py the
# Dockerfile COPYs, plus serve.py and the Dockerfile — exactly like the sibling
# szl-holdings/a11oy hf-sync-backend. env.APP_FILES is the curated trigger list
# (kept in lockstep with on.push.paths); it is NOT the keep-set.
#
# delete-aware (matches a11oy): besides pushing only the files whose content
# differs from the Space (so an unchanged set is a true no-op), it also DELETES,
# in the SAME commit, any backend .py present on the Space but no longer in the
# computed mirror set (Dockerfile COPY + serve.py) — so a module removed from
# the repo + Dockerfile COPY set stops lingering in the Space tree. Deletion is
# scoped to backend .py ONLY: it never touches README, the front-door
# pages/web HTML+JS, the built SPA bundles, or LFS/vendor blobs (static/,
# static-vendor/). The delete keep-set is the FULL Dockerfile-COPY set (NOT the
# curated APP_FILES subset) precisely so a real module is never deleted.
#
# After a real commit it triggers a HuggingFace factory rebuild
# (api.restart_space factory_reboot=True) so the mirrored code actually goes
# live with no manual step. Idempotent: an in-sync repo makes no commit and
# triggers NO rebuild.
#
# The push/sweep logic lives in .github/scripts/hf_sync_backend.py (extracted so
# the SAME code is exercised by the network-free self-test
# .github/scripts/test_hf_sync_backend.py, run by hf-sync-backend-selftest.yml).
mirror-app:
needs: detect
if: needs.detect.outputs.app == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 1
lfs: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- name: Install huggingface_hub
run: pip install --quiet "huggingface_hub>=0.25"
- name: Mirror backend (.py + Dockerfile) to the Space delete-aware
env:
HF_WRITE_TOKEN: ${{ secrets.HF_WRITE_TOKEN }}
SPACE_ID: SZLHOLDINGS/killinchu
run: |
set -euo pipefail
if [ -z "${HF_WRITE_TOKEN:-}" ]; then
echo "::error::HF_WRITE_TOKEN secret is not set — cannot mirror app files to the Space."
echo "::error::Founder action: add repo secret HF_WRITE_TOKEN (HF write token, org-write to SZLHOLDINGS)."
exit 1
fi
python3 .github/scripts/hf_sync_backend.py