Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/hardening-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ on:
- 'pmoves/docker-compose*.yml'
- 'pmoves/services/**/Dockerfile*'
- '.github/workflows/hardening-validation.yml'
- '.github/workflows/integrations-ghcr.matrix.json'
- 'pmoves/integrations/archon'
Comment on lines +10 to +11

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/hardening-validation.yml"

echo "=== File existence / size ==="
ls -l "$FILE" || true
echo

echo "=== Lines 1-80 ==="
nl -ba "$FILE" | sed -n '1,120p'
echo

echo "=== Search for specific path entries ==="
rg -n "integrations-ghcr\.matrix\.json|pmoves/integrations/archon" "$FILE" || true
echo

echo "=== Search for ghcr_local_prepublish step ==="
rg -n "ghcr_local_prepublish\.py|--paths-only" "$FILE" || true
echo

echo "=== Lines around ghcr_local_prepublish invocation (if found) ==="
# If we found a match, print a window around the first match line
LINE=$(rg -n "ghcr_local_prepublish\.py" "$FILE" | head -n1 | cut -d: -f1 || true)
if [[ -n "${LINE:-}" ]]; then
  START=$((LINE-40))
  END=$((LINE+60))
  nl -ba "$FILE" | sed -n "${START},${END}p"
else
  echo "No ghcr_local_prepublish.py invocation found."
fi

echo "=== Search for StepSecurity presence ==="
rg -n "StepSecurity|stepsecurity|security" "$FILE" || true

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 272


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/hardening-validation.yml"

echo "=== File existence / size ==="
ls -l "$FILE" || true
echo

echo "=== Lines 1-140 ==="
nl -ba "$FILE" | sed -n '1,160p'
echo

echo "=== Search for specific path entries ==="
rg -n "integrations-ghcr\.matrix\.json|pmoves/integrations/archon" "$FILE" || true
echo

echo "=== Search for ghcr_local_prepublish step ==="
rg -n "ghcr_local_prepublish\.py|--paths-only" "$FILE" || true
echo

echo "=== Lines around ghcr_local_prepublish invocation ==="
LINE=$(rg -n "ghcr_local_prepublish\.py" "$FILE" | head -n1 | cut -d: -f1 || true)
if [[ -n "${LINE:-}" ]]; then
  START=$((LINE-60))
  END=$((LINE+80))
  nl -ba "$FILE" | sed -n "${START},${END}p"
fi

echo "=== Search for StepSecurity presence ==="
rg -n "StepSecurity|stepsecurity|step-security|Step Security" "$FILE" || true

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 273


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/hardening-validation.yml"

echo "=== Lines 1-140 (with line numbers via awk) ==="
awk '{printf "%d\t%s\n", NR, $0}' "$FILE" | sed -n '1,140p'

echo
echo "=== Search for specific path entries ==="
rg -n "integrations-ghcr\.matrix\.json|pmoves/integrations/archon" "$FILE" || true

echo
echo "=== Search for ghcr_local_prepublish step ==="
rg -n "ghcr_local_prepublish\.py|--paths-only" "$FILE" || true

echo
echo "=== Show StepSecurity/secret-hardening markers ==="
rg -n "StepSecurity|stepsecurity|step-security|secrets|token|registry" "$FILE" || true

echo
echo "=== Show context around first match for ghcr_local_prepublish.py ==="
MATCH_LINE=$(rg -n "ghcr_local_prepublish\.py" "$FILE" | head -n1 | cut -d: -f1 || true)
if [[ -n "${MATCH_LINE:-}" ]]; then
  START=$((MATCH_LINE-60))
  END=$((MATCH_LINE+60))
  awk '{printf "%d\t%s\n", NR, $0}' "$FILE" | sed -n "${START},${END}p"
fi

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 12580


🌐 Web query:

GitHub Actions workflow trigger paths filter match directory without wildcard paths: - some/dirvssome/dir/**``

💡 Result:

In GitHub Actions, the behavior of path filters depends on the glob pattern provided, as the system follows standard glob matching rules [1][2]. Using paths: - some/dir When you specify a directory path without a wildcard, GitHub Actions interprets this as a pattern that matches the directory itself and any files located exactly within that directory [2]. However, it does not automatically include files in nested subdirectories [2]. For example, some/dir will trigger on some/dir/file.txt but will not trigger on some/dir/subdir/file.txt. Using paths: - some/dir/ The `` wildcard is the recursive glob operator [13]. By appending /, you explicitly instruct the filter to match all files within the specified directory and all of its nested subdirectories, regardless of depth [2]. This is the standard way to ensure that any change within a directory tree triggers the workflow. Summary of Differences: - `some/dir`: Matches files directly inside `some/dir` only. - `some/dir/`: Matches files inside `some/dir` and all files in any subdirectories recursively. If your goal is to trigger the workflow whenever any file changes within a directory tree, `some/dir/` is the correct and necessary syntax [2]. Both patterns are treated as glob expressions evaluated relative to the root of the repository [2].

Citations:


Broaden Archon path filter so nested changes trigger the GHCR matrix validation

The workflow on: push/pull_request: paths entries add only pmoves/integrations/archon (lines 11 and 19). That non-recursive glob won’t trigger on changes in subdirectories under pmoves/integrations/archon/, so the new GHCR path gate can be skipped for the Archon changes it’s meant to validate. The added python3 pmoves/tools/ghcr_local_prepublish.py --paths-only step is otherwise wired correctly, and StepSecurity hardening remains present.

Suggested fix
-      - 'pmoves/integrations/archon'
+      - 'pmoves/integrations/archon/**'
...
-      - 'pmoves/integrations/archon'
+      - 'pmoves/integrations/archon/**'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- '.github/workflows/integrations-ghcr.matrix.json'
- 'pmoves/integrations/archon'
- '.github/workflows/integrations-ghcr.matrix.json'
- 'pmoves/integrations/archon/**'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/hardening-validation.yml around lines 10 - 11, The paths
filter for the workflow currently lists the non-recursive path
'pmoves/integrations/archon' which won't match changes in nested files; update
both occurrences of that path in the workflow's on: push/pull_request: paths
array to a recursive glob like 'pmoves/integrations/archon/**' so subdirectory
changes trigger the GHCR matrix validation (leave the existing
'.github/workflows/integrations-ghcr.matrix.json' entry and the prepublish step
'python3 pmoves/tools/ghcr_local_prepublish.py --paths-only' unchanged).

pull_request:
branches: [main, PMOVES.AI-Edition-Hardened-Integrations, PMOVES.AI-Edition-Hardened]
paths:
- 'pmoves/docker-compose*.yml'
- 'pmoves/services/**/Dockerfile*'
- '.github/workflows/hardening-validation.yml'
- '.github/workflows/integrations-ghcr.matrix.json'
- 'pmoves/integrations/archon'
workflow_dispatch:

concurrency:
Expand Down Expand Up @@ -400,6 +404,13 @@ jobs:
echo "✓ pmoves/monitoring/docker-compose.monitoring.yml is valid"
fi

- name: Validate GHCR matrix paths
run: |
python3 pmoves/tools/ghcr_local_prepublish.py \
--matrix-file .github/workflows/integrations-ghcr.matrix.json \
--repo-root . \
--paths-only

- name: Check for network segmentation
run: |
echo "Checking network segmentation..."
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/sync-secrets-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ jobs:
if-no-files-found: warn

- name: Summary
shell: bash
run: |
# Validate that matrix.target only contains safe label characters.
# matrix.target is a workflow_dispatch string input — it's template-interpolated
Expand All @@ -366,9 +367,15 @@ jobs:
echo " source pmoves/scripts/bootstrap_credentials.sh"
if [ -f "pmoves/data/chit/env.cgp.json" ]; then
echo ""
echo "Pattern B pull (non-runner nodes, e.g. Z890/4090):"
echo "Pattern B pull (non-runner nodes):"
echo " # Unix/Linux:"
echo " gh run download ${{ github.run_id }} --repo POWERFULMOVES/PMOVES.AI \\"
echo " --name chit-bundle-$_target-${{ github.run_id }} \\"
echo " --dir \"\${XDG_CONFIG_HOME:-\$HOME/.config}/pmoves/chit\""
echo " # Windows (4090):"
echo " gh run download ${{ github.run_id }} --repo POWERFULMOVES/PMOVES.AI \\"
echo " --name chit-bundle-$_target-${{ github.run_id }} \\"
echo " --dir \"\$XDG_CONFIG_HOME/pmoves/chit\""
echo " make -C pmoves secrets-funnel-sync"
echo " --dir \"\$APPDATA/pmoves/chit\""
echo " # Then materialize (preserves bundle — does NOT overwrite with local keys):"
echo " make -C pmoves secrets-funnel-sync-from-bundle"
fi
231 changes: 230 additions & 1 deletion pmoves/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ supa-start: ensure-env-shared ## Start Supabase stack for selected runtime (cli
-e KONG_PG_PASSWORD=$${SUPABASE_DB_PASSWORD:-postgres} \
kong:3.7.1 kong migrations bootstrap --yes >/dev/null 2>&1 || true; \
$(MAKE) --no-print-directory supa-bootstrap-db; \
$(DC) up -d --force-recreate supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler; \
$(DC) --profile supabase-local up -d --force-recreate supabase-postgrest supabase-gotrue supabase-kong supabase-realtime supabase-storage supabase-studio supabase-imgproxy supabase-meta supabase-edge-functions supabase-analytics supabase-vector supabase-pooler; \
fi
@$(MAKE) --no-print-directory supa-status
@$(MAKE) --no-print-directory supa-collation-refresh 2>/dev/null || true
Expand All @@ -423,6 +423,12 @@ supa-restart: ## Restart Supabase stack for selected runtime
@sleep 2
@$(MAKE) --no-print-directory supa-start

.PHONY: pooler-recreate
pooler-recreate: ## Force-recreate supabase-pooler container to pick up env file changes (non-disruptive)
@echo "→ Force-recreating supabase-pooler with current env..."
@$(DC) --profile supabase-local up -d --force-recreate supabase-pooler
@echo "✓ pooler recreated — give it 30s for health check"
Comment on lines +426 to +430

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard pooler-recreate against CLI runtime.

Lines 427-429 always start supabase-pooler through compose. If SUPABASE_RUNTIME=cli, this bypasses the existing runtime-guard flow and creates mixed Supabase state on the same machine. This target should fail fast unless the runtime is compose, or call the same guard used by supa-start.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/Makefile` around lines 426 - 430, The pooler-recreate Makefile target
currently always recreates supabase-pooler; guard it the same way as supa-start
by checking SUPABASE_RUNTIME (or invoking the same guard target used by
supa-start) and fail fast unless SUPABASE_RUNTIME is "compose"; specifically
update the pooler-recreate target to verify SUPABASE_RUNTIME (or call the
existing guard target/function) before running @$(DC) --profile supabase-local
up -d --force-recreate supabase-pooler and print a clear error and non-zero exit
when the runtime is not compose.


supa-status: ## Show Supabase status for selected runtime and export env snapshot when available
@echo "🔍 Supabase status (SUPABASE_RUNTIME=$(SUPABASE_RUNTIME)):"
@if [ "$(SUPABASE_RUNTIME)" = "cli" ]; then \
Expand Down Expand Up @@ -637,6 +643,50 @@ supabase-bootstrap: ## Apply pending Supabase migrations + seeds (tracked in pub
fi
@echo "✅ Supabase bootstrap complete"

.PHONY: supabase-bootstrap-no-start
supabase-bootstrap-no-start: ## Apply migrations+seeds against already-running DB (skips supa-start; uses SUPABASE_DB_USER)
@echo "🗄️ Applying Supabase schema + seeds (no-start mode)..."
@set -euo pipefail; \
db=$$(bash "$(SUPABASE_DB_HELPER)" running); \
if [ -z "$$db" ]; then echo "❌ Supabase DB container not found — start it first"; exit 1; fi; \
pg_user=$$(docker exec "$$db" sh -c 'echo $${POSTGRES_USER:-postgres}'); \
echo " DB container: $$db | pg_user: $$pg_user"; \
_psql() { docker exec -i "$$db" psql -U "$$pg_user" -h 127.0.0.1 -d postgres "$$@"; }; \
_psql -v ON_ERROR_STOP=1 -c "CREATE TABLE IF NOT EXISTS public.pmoves_bootstrap_history (kind text NOT NULL, filename text NOT NULL, applied_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (kind, filename));"; \
if [ -d "supabase/migrations" ]; then \
for migration in $$(find supabase/migrations -maxdepth 1 -type f -name '*.sql' | LC_ALL=C sort); do \
[ -f "$$migration" ] || continue; \
name=$$(basename "$$migration"); \
applied=$$(_psql -tAc "SELECT 1 FROM public.pmoves_bootstrap_history WHERE kind='migration' AND filename='$$name' LIMIT 1;" | tr -d '[:space:]'); \
if [ "$$applied" = "1" ]; then \
echo " SKIP (applied): $$name"; \
continue; \
fi; \
echo " APPLY: $$name"; \
_psql < "$$migration" && \
_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind,filename) VALUES('migration','$$name') ON CONFLICT DO NOTHING;" || \
echo " WARN: $$name failed — continuing"; \
Comment on lines +665 to +668

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t treat “applied but not recorded” as a warning.

The apply && insert-history || warn chain collapses two different failures into one path. If the SQL applies successfully but the pmoves_bootstrap_history insert fails, the target continues and the next run will replay that already-applied file against a mutated database.

Split the flow so only SQL execution failures are skippable; once a file has been applied, failure to record it should stop the target.

Also applies to: 680-683

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/Makefile` around lines 665 - 668, The current shell chain conflates
SQL execution failure and history-insert failure (using _psql < "$$migration" &&
_psql -c "INSERT INTO public.pmoves_bootstrap_history(...)" || echo ...) so an
insert failure will be treated as a non-fatal warning; change the flow so you
first run _psql < "$$migration" and if that fails print the warning and
continue, but if it succeeds then run the INSERT into pmoves_bootstrap_history
and if that INSERT fails exit non-zero (stop the target). Update the block
around the _psql invocation and the INSERT (and the analogous block at lines
680-683) to use an if/then/else or separate conditional commands that only
continue on a failed SQL apply, and abort when the history INSERT
(pmoves_bootstrap_history, filename/migration variables, _psql -c) fails.

done; \
fi; \
if [ -d "supabase/initdb" ]; then \
for seed in $$(find supabase/initdb -maxdepth 1 -type f -name '*.sql' | LC_ALL=C sort); do \
[ -f "$$seed" ] || continue; \
name=$$(basename "$$seed"); \
applied=$$(_psql -tAc "SELECT 1 FROM public.pmoves_bootstrap_history WHERE kind='seed' AND filename='$$name' LIMIT 1;" | tr -d '[:space:]'); \
if [ "$$applied" = "1" ]; then \
echo " SKIP (applied): $$name"; \
continue; \
fi; \
echo " APPLY seed: $$name"; \
_psql < "$$seed" && \
_psql -c "INSERT INTO public.pmoves_bootstrap_history(kind,filename) VALUES('seed','$$name') ON CONFLICT DO NOTHING;" || \
echo " WARN: seed $$name failed — continuing"; \
done; \
else \
echo " ⚠️ No initdb directory found"; \
fi
@echo "✅ Supabase bootstrap (no-start) complete"

supabase-bootstrap-mark-applied: ## Mark all migration/seed files as applied in bootstrap history (no SQL execution)
@echo "📝 Marking migrations/seeds as applied in public.pmoves_bootstrap_history..."
@$(MAKE) --no-print-directory supa-start >/dev/null
Expand Down Expand Up @@ -1433,6 +1483,74 @@ bootstrap-tier-envs: ## Create missing tier env files from examples (Hardened br
echo "✓ All tier env files already exist."; \
fi

.PHONY: tier-data-patch-missing
tier-data-patch-missing: ## Append compose-required keys missing from env.tier-data (idempotent)
@if [ ! -f env.tier-data ]; then echo "env.tier-data not found"; exit 1; fi; \
changed=0; \
for key in QDRANT__API_KEY NEO4J_PASSWORD; do \
if ! grep -q "^$$key=" env.tier-data 2>/dev/null; then \
val=$$(openssl rand -hex 32); \
echo "$$key=$$val" >> env.tier-data; \
echo "→ Appended $$key to env.tier-data"; \
changed=1; \
fi; \
done; \
if ! grep -q "^MINIO_USER=" env.tier-data 2>/dev/null; then \
echo "MINIO_USER=minioadmin" >> env.tier-data; \
echo "→ Appended MINIO_USER to env.tier-data"; \
changed=1; \
fi; \
if ! grep -q "^MINIO_PASSWORD=" env.tier-data 2>/dev/null; then \
val=$$(openssl rand -base64 24 | tr -d '\n='); \
echo "MINIO_PASSWORD=$$val" >> env.tier-data; \
echo "→ Appended MINIO_PASSWORD to env.tier-data"; \
changed=1; \
fi; \
if ! grep -q "^WGER_DB_PASSWORD=" env.tier-data 2>/dev/null; then \
val=$$(openssl rand -base64 24 | tr -d '\n='); \
echo "WGER_DB_PASSWORD=$$val" >> env.tier-data; \
echo "→ Appended WGER_DB_PASSWORD to env.tier-data"; \
changed=1; \
fi; \
if [ "$$changed" = "0" ]; then echo "✓ env.tier-data already has all required keys"; fi

.PHONY: tier-api-patch-missing
tier-api-patch-missing: ## Append compose-required keys missing from env.tier-api (idempotent)
@if [ ! -f env.tier-api ]; then echo "env.tier-api not found"; exit 1; fi; \
changed=0; \
for key in WGER_SECRET_KEY WGER_ADMIN_PASSWORD MCP_SERVER_TOKEN; do \
if ! grep -q "^$$key=" env.tier-api 2>/dev/null; then \
val=$$(openssl rand -base64 32 | tr -d '\n='); \
echo "$$key=$$val" >> env.tier-api; \
echo "→ Appended $$key to env.tier-api"; \
changed=1; \
fi; \
done; \
if [ "$$changed" = "0" ]; then echo "✓ env.tier-api already has all required keys"; fi

.PHONY: tier-supabase-patch-missing
tier-supabase-patch-missing: ## Append/fix compose-required keys in env.tier-supabase (idempotent)
@if [ ! -f env.tier-supabase ]; then echo "env.tier-supabase not found"; exit 1; fi; \
changed=0; \
for key in SECRET_KEY_BASE LOGFLARE_PUBLIC_ACCESS_TOKEN LOGFLARE_PRIVATE_ACCESS_TOKEN; do \
if ! grep -q "^$$key=" env.tier-supabase 2>/dev/null; then \
val=$$(openssl rand -base64 48 | tr -d '\n=' | cut -c1-64); \
echo "$$key=$$val" >> env.tier-supabase; \
echo "→ Appended $$key to env.tier-supabase"; \
changed=1; \
fi; \
done; \
_vault_val=$$(grep "^VAULT_ENC_KEY=" env.tier-supabase 2>/dev/null | cut -d= -f2-); \
if [ -z "$$_vault_val" ]; then \
echo "VAULT_ENC_KEY=$$(openssl rand -hex 16)" >> env.tier-supabase; \
echo "→ Appended VAULT_ENC_KEY (32-char hex)"; changed=1; \
elif [ "$${#_vault_val}" -ne 32 ]; then \
_new_vault=$$(openssl rand -hex 16); \
sed -i "s|^VAULT_ENC_KEY=.*|VAULT_ENC_KEY=$$_new_vault|" env.tier-supabase; \
echo "→ Fixed VAULT_ENC_KEY (was $${#_vault_val} chars, now 32)"; changed=1; \
fi; \
if [ "$$changed" = "0" ]; then echo "✓ env.tier-supabase already has all required keys"; fi

.PHONY: populate-tier-envs
populate-tier-envs: bootstrap-tier-envs ## Populate tier env files with defaults from env.shared and .env.local
@echo "Populating tier env files with defaults..."
Expand Down Expand Up @@ -1749,6 +1867,110 @@ integration-contract-check-strict: ## Strict integration contract check (missing
integration-contract-check-baseline: ## Strict contract checks for template + baseline overlays
@$(PYTHON) tools/integration_contract_check.py $(INTEGRATION_CONTRACT_BASELINE) --strict-hooks

CF_PAGES_PROJECT ?= cataclysmstudios
CF_PAGES_DIR ?= ../deploy/cataclysmstudios
CF_PAGES_BRANCH ?= main

CF_PAGES_PORT ?= 8788

.PHONY: cf-pages-dev cf-pages-create cf-pages-deploy cf-pages-status
cf-pages-dev: ## Serve cataclysmstudios locally via wrangler pages dev (http://localhost:CF_PAGES_PORT)
@echo "→ Previewing $(CF_PAGES_PROJECT) at http://localhost:$(CF_PAGES_PORT)"
npx wrangler pages dev "$(CF_PAGES_DIR)" --port $(CF_PAGES_PORT)
cf-pages-create: ensure-env-shared ## Create Cloudflare Pages project (one-time bootstrap)
@$(LOAD_ENV_SHARED); \
if [ -z "$${CLOUDFLARE_API_TOKEN:-}" ]; then \
echo "❌ CLOUDFLARE_API_TOKEN not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
if [ -z "$${CLOUDFLARE_ACCOUNT_ID:-}" ]; then \
echo "❌ CLOUDFLARE_ACCOUNT_ID not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
echo "→ Creating Cloudflare Pages project: $(CF_PAGES_PROJECT)"; \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages project create "$(CF_PAGES_PROJECT)" \
--production-branch main 2>&1; \
echo "✅ CF Pages project created — now run: make cf-pages-deploy"

cf-pages-deploy: ensure-env-shared ## Deploy cataclysmstudios static site to Cloudflare Pages
@$(LOAD_ENV_SHARED); \
if [ -z "$${CLOUDFLARE_API_TOKEN:-}" ]; then \
echo "❌ CLOUDFLARE_API_TOKEN not set — run: make secrets-funnel-sync"; \
exit 1; \
fi; \
if [ -z "$${CLOUDFLARE_ACCOUNT_ID:-}" ]; then \
echo "❌ CLOUDFLARE_ACCOUNT_ID not set — run: make secrets-funnel-sync"; \
exit 1; \
fi; \
echo "→ Deploying $(CF_PAGES_PROJECT) to Cloudflare Pages..."; \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages deploy "$(CF_PAGES_DIR)" \
--project-name "$(CF_PAGES_PROJECT)" \
--branch "$(CF_PAGES_BRANCH)" \
--commit-dirty=true 2>&1; \
echo "✅ CF Pages deploy complete"

cf-pages-status: ensure-env-shared ## Check Cloudflare Pages project status
@$(LOAD_ENV_SHARED); \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages project list 2>&1 | grep -i "$(CF_PAGES_PROJECT)" || echo "(project not found)"

PMOVES_AI_PROJECT ?= pmoves-ai
PMOVES_AI_DIR ?= ../website
PMOVES_AI_BRANCH ?= main
PMOVES_AI_PORT ?= 8789

.PHONY: pmoves-ai-dev pmoves-ai-create pmoves-ai-deploy pmoves-ai-status
pmoves-ai-dev: ## Serve pmoves.ai locally via wrangler pages dev (http://localhost:PMOVES_AI_PORT)
@echo "→ Previewing $(PMOVES_AI_PROJECT) at http://localhost:$(PMOVES_AI_PORT)"
npx wrangler pages dev "$(PMOVES_AI_DIR)" --port $(PMOVES_AI_PORT)

pmoves-ai-create: ensure-env-shared ## Create pmoves-ai Cloudflare Pages project (one-time bootstrap)
@$(LOAD_ENV_SHARED); \
if [ -z "$${CLOUDFLARE_API_TOKEN:-}" ]; then \
echo "❌ CLOUDFLARE_API_TOKEN not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
if [ -z "$${CLOUDFLARE_ACCOUNT_ID:-}" ]; then \
echo "❌ CLOUDFLARE_ACCOUNT_ID not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
echo "→ Creating Cloudflare Pages project: $(PMOVES_AI_PROJECT)"; \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages project create "$(PMOVES_AI_PROJECT)" \
--production-branch main 2>&1; \
echo "✅ pmoves-ai Pages project created — now run: make pmoves-ai-deploy"

pmoves-ai-deploy: ensure-env-shared ## Deploy pmoves.ai static site to Cloudflare Pages
@$(LOAD_ENV_SHARED); \
if [ -z "$${CLOUDFLARE_API_TOKEN:-}" ]; then \
echo "❌ CLOUDFLARE_API_TOKEN not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
if [ -z "$${CLOUDFLARE_ACCOUNT_ID:-}" ]; then \
echo "❌ CLOUDFLARE_ACCOUNT_ID not set — run: make secrets-funnel-sync-from-bundle"; \
exit 1; \
fi; \
echo "→ Deploying $(PMOVES_AI_PROJECT) to Cloudflare Pages (branch: $(PMOVES_AI_BRANCH))..."; \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages deploy "$(PMOVES_AI_DIR)" \
--project-name "$(PMOVES_AI_PROJECT)" \
--branch "$(PMOVES_AI_BRANCH)" \
--commit-dirty=true 2>&1; \
echo "✅ pmoves-ai deploy complete"

pmoves-ai-status: ensure-env-shared ## Check pmoves-ai Cloudflare Pages project status
@$(LOAD_ENV_SHARED); \
CLOUDFLARE_API_TOKEN="$${CLOUDFLARE_API_TOKEN}" \
CLOUDFLARE_ACCOUNT_ID="$${CLOUDFLARE_ACCOUNT_ID}" \
npx wrangler pages project list 2>&1 | grep -i "$(PMOVES_AI_PROJECT)" || echo "(pmoves-ai project not found)"

up-cloudflare: ensure-env-shared ## Start the Cloudflare tunnel connector (profile=cloudflare)
@$(LOAD_ENV_SHARED); \
if [ -z "$$CLOUDFLARE_TUNNEL_TOKEN" ] && [ -z "$$CLOUDFLARE_TUNNEL_NAME" ]; then \
Expand Down Expand Up @@ -2716,6 +2938,13 @@ ghcr-dispatch-one: ci-runners-check-strict ## Dispatch GHCR workflow for a singl
ghcr-list: ## List all images in the integrations-ghcr matrix
@$(PYTHON) -c "import json,pathlib;[print(e['name']) for e in json.loads(pathlib.Path('$(GHCR_MATRIX_FILE)').read_text())]"

.PHONY: ghcr-matrix-paths-check
ghcr-matrix-paths-check: ## Validate all in-repo GHCR matrix context/dockerfile paths exist (no Docker build)
@$(PYTHON) $(GHCR_PREPUBLISH_SCRIPT) \
--matrix-file "$(GHCR_MATRIX_FILE)" \
--repo-root .. \
--paths-only

.PHONY: deepresearch-smoke
deepresearch-smoke: ## Publish a sample DeepResearch request and wait for a result (requires worker running)
@ENV_FILE="$(CURDIR)/env.shared" bash -lc '. ./scripts/with-env.sh "$$ENV_FILE" && PYTHONPATH="$(CURDIR)/.." python3 tools/deepresearch_smoke.py --timeout $${DEEPRESEARCH_SMOKE_TIMEOUT:-60}'
Expand Down
33 changes: 33 additions & 0 deletions pmoves/docs/AGENTS/AGNOTE4482.md
Original file line number Diff line number Diff line change
Expand Up @@ -1161,3 +1161,36 @@ No open PR existed for `codex/big-ball-5090-gap-closure` at the time of this not
- Timestamp: `2026-05-26`

<!-- GRAPHITI_MARK: CODEX-GPT5::BIG-BALL-5090-GAP-CLOSURE::2026-05-26 -->

## Antigravity CLI A2UI Hologram Scaling Fix (2026-05-30)

### Context
Operator requested fixing the "identical pink dot" gallery issue stemming from the pending `A2UI Remotion hologram viewport scaling (1920x1080 viewport)` ticket. The `geometry_mesh` element in `a2ui-renderer` was stubbed out and required DGX SPARK physical access.

This work ran on the local workspace `3fd5d899-f774-45da-bae1-ef349bf01951` targeting branch `fix/ghcr-matrix-paths-gate` in the parent PMOVES repo.

### Work Performed
- Bypassed the stubbed Remotion 2D generator and implemented a live interactive 3D WebGL solution on the landing page.
- Upgraded `website/hyperdim/index.html` with URL parameter parsing (`?preset=` and `?ui=none`) for headless preset embedding.
- Generated three distinct parametric topology presets derived from `beats_constellation.json`:
- `beats_c5.json`: Allegro Balanced Bright (High tempo, bright color)
- `beats_c3.json`: Allegro Balanced Deep (Moderate tempo, deep color)
- `beats_c1.json`: Cluster 1 (High fitness, tight curvature, very bright)
- Replaced the three static `<video>` elements in `website/index.html` gallery with `<iframe>` embeds targeting the Hyperdimensions viewer, successfully resolving the 1920x1080 scaling issue via live rendering.

Comment on lines +1167 to +1180

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistency between audit entry and PR scope.

The Context section describes fixing an "identical pink dot" gallery issue (line 1168), but the PR title and summary state this PR "resolves black WebGL canvas issues in the default and embed viewers." The Work Performed section lists gallery iframe replacements but omits the core technical fixes mentioned in the PR summary:

  1. Black canvas fix: "ensuring the default nautilus fallback evaluates the surface function and forcing the Three.js renderer to recalculate geometry when the sidebar collapses in ui=none mode"
  2. Playlist link update: PR summary mentions "replaces a TODO with the requested YouTube playlist link for DARKXSIDE'S School"

The audit trail should accurately reflect all work performed in this PR. Either reconcile the "pink dot" vs "black canvas" discrepancy or document both issues if they're related.

Suggested additions to Work Performed

Add after line 1173:

 ### Work Performed
+- Fixed black WebGL canvas rendering issues in Hyperdimensions viewer:
+  - Ensured default nautilus preset evaluates the surface function properly
+  - Added geometry recalculation trigger when sidebar collapses in `ui=none` embed mode
 - Bypassed the stubbed Remotion 2D generator and implemented a live interactive 3D WebGL solution on the landing page.

Add after line 1179:

   - `beats_c1.json`: Cluster 1 (High fitness, tight curvature, very bright)
 - Replaced the three static `<video>` elements in `website/index.html` gallery with `<iframe>` embeds targeting the Hyperdimensions viewer, successfully resolving the 1920x1080 scaling issue via live rendering.
+- Updated Cloudflare School playlist button URL to link DARKXSIDE'S School playlist.

Based on coding guidelines: AGNOTE4482 protocol requires documenting UI fixes as trail entries. As per coding guidelines, the documented fix direction includes recording additional UI fixes applied.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/docs/AGENTS/AGNOTE4482.md` around lines 1167 - 1180, Update the
AGNOTE4482 audit entry to reconcile the mismatch between the "identical pink
dot" context and the PR summary by explicitly documenting both UI fixes: include
the "black canvas fix" details (ensure the default nautilus fallback evaluates
the surface function and force the Three.js renderer to recalculate geometry
when the sidebar collapses in ui=none mode) and note the playlist link change
(replace the TODO with the requested YouTube playlist link for DARKXSIDE'S
School); adjust the Context and Work Performed sections so they mention both the
gallery iframe replacement and these two core technical fixes so the audit trail
accurately reflects all changes in this PR.

### Lane Status
| Lane | Status | Notes |
|------|--------|-------|
| A2UI Hologram Scaling | Resolved (Live WebGL) | DGX SPARK dependency bypassed. Rendering now happens live in the browser via Three.js. |
| Custom Domain Linking | Handoff | Operator to configure `pmoves.ai` domain in Cloudflare dashboard manually. |

### PR Readiness
The branch is ready to commit the UI changes. Proposed logical commit:
`feat(website): replace A2UI mp4s with live Hyperdimensions WebGL embeds to fix 1920x1080 scaling`

### Agent ACK
- Agent: `ANTIGRAVITY-GEMINI`
- Signature: `ACK::ANTIGRAVITY-GEMINI::A2UI-HOLOGRAM-SCALING-FIX`
- Timestamp: `2026-05-30`

<!-- GRAPHITI_MARK: ANTIGRAVITY-GEMINI::A2UI-HOLOGRAM-SCALING-FIX::2026-05-30 -->
Comment on lines +1165 to +1196

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing AGNOTE4482 signoff checklist update.

The AGNOTE4482 lane protocol requires updating the shared signoff gate (AGNOTE4482_SIGNOFF_CHECKLIST.md) with section-level ACKs. This audit entry documents completed work but doesn't reference which signoff checklist sections were validated or marked complete.

Per the protocol defined at lines 19-23: "Each participating agent signs only for the sections they actually reviewed or executed. Merge readiness is a multi-agent decision, not a single-agent vibe check."

Suggested addition

Add after line 1189:

 The branch is ready to commit the UI changes. Proposed logical commit:
 `feat(website): replace A2UI mp4s with live Hyperdimensions WebGL embeds to fix 1920x1080 scaling`
 
+### Signoff Checklist Status
+Updated `AGNOTE4482_SIGNOFF_CHECKLIST.md`:
+- ✅ §[X.X] [Description of relevant checklist section]
+- ✅ §[Y.Y] [Description of relevant checklist section]
+
 ### Agent ACK

Based on coding guidelines: agents must update the shared signoff gate (AGNOTE4482_SIGNOFF_CHECKLIST) with section-level ACKs.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 1182-1182: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/docs/AGENTS/AGNOTE4482.md` around lines 1165 - 1196, Update the shared
AGNOTE4482_SIGNOFF_CHECKLIST to record section-level ACKs for this PR: add
entries naming the validated sections (e.g., "A2UI Hologram Scaling", "Custom
Domain Linking"), include the agent identifier ANTIGRAVITY-GEMINI and the
signature ACK::ANTIGRAVITY-GEMINI::A2UI-HOLOGRAM-SCALING-FIX with the timestamp
2026-05-30, and mark which specific checklist items this agent
reviewed/validated (only the items actually executed), so the checklist reflects
multi-agent merge readiness rather than a single-agent vibe check.

10 changes: 10 additions & 0 deletions pmoves/mk/codex.mk
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ secrets-runtime-hydrate: ensure-env-shared ## Pull runtime-emitted labels (Supab
secrets-funnel-sync: chit-manifest-sync chit-export ## Materialize generated env files from CHIT + secrets manifest
@PYTHONPATH="$(CURDIR)/.." $(CODEX_PY) tools/secrets_sync.py generate --manifest pmoves/chit/secrets_manifest.yaml --cgp "$(CHIT_EXPORT_PATH)" $(SECRETS_SYNC_FLAGS)

.PHONY: secrets-funnel-sync-from-bundle
secrets-funnel-sync-from-bundle: chit-manifest-sync ## Materialize env files from a pre-installed CI CHIT bundle (skips chit-export so CI credentials are not overwritten)
@if [ ! -f "$(CHIT_EXPORT_PATH)" ]; then \
echo "❌ No bundle at $(CHIT_EXPORT_PATH) — download via:"; \
echo " gh run download <RUN_ID> --repo POWERFULMOVES/PMOVES.AI --name chit-bundle-4090-<RUN_ID> --dir \"\$$(dirname $(CHIT_EXPORT_PATH))\""; \
exit 1; \
fi
@echo "→ Reading CHIT bundle from $(CHIT_EXPORT_PATH)"
@PYTHONPATH="$(CURDIR)/.." $(CODEX_PY) tools/secrets_sync.py generate --manifest pmoves/chit/secrets_manifest.yaml --cgp "$(CHIT_EXPORT_PATH)" $(SECRETS_SYNC_FLAGS)

secrets-funnel: ## Portable secrets flow: local hydrate -> CHIT export -> manifest sync -> audit gates (FORCE=1 to overwrite stale)
@$(MAKE) --no-print-directory secrets-local-hydrate
@$(MAKE) --no-print-directory secrets-runtime-hydrate
Expand Down
Loading
Loading