This monorepo is public. Internal content (positioning, competitive
briefs, sales playbooks, PMM/press drip, draft campaigns) belongs in
Molecule-AI/internal — never here.
## What this PR removes
/research/ (3 competitive briefs)
/marketing/ (45 files: assets, audio, community, copy,
demos, devrel, drip, pmm, press, sales)
/docs/marketing/ (31 draft campaign / blog / brief files)
comment-1172.json + comment-1173.json
test-pmm-temp.txt
tick-reflections-temp.md
83 files removed, 7,141 lines deleted from public history (going forward —
historical commits remain visible in this repo's git log).
## Companion: internal repo absorption
Molecule-AI/internal PR `chore/migrate-monorepo-internal-content-2026-04-23`
absorbs all 79 files into `from-monorepo-2026-04-23/` for curator triage
into the existing internal/marketing/ tree. Bulk-dump avoids file-collision
on overlapping subdirs (audio, devrel, pmm).
## Three-layer enforcement so this can't recur
1. .gitignore — blocks `git add` of /research, /marketing, /docs/marketing,
/comment-*.json, *-temp.{md,txt}, /test-pmm-*, /tick-reflections-*
2. .github/workflows/block-internal-paths.yml — CI hard gate. Fails any PR
that adds a forbidden path. Cannot be silently bypassed.
3. docs/internal-content-policy.md — canonical decision tree for agents
and humans. Linked from the CI failure message.
A separate PR on molecule-ai-org-template-molecule-dev updates SHARED_RULES
to teach every agent role to write internal content directly to
Molecule-AI/internal via gh repo clone + commit + PR (the prevention-at-
source layer; this PR is the mechanical backstop).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
3.7 KiB
YAML
96 lines
3.7 KiB
YAML
name: Block internal-flavored paths
|
|
|
|
# Hard CI gate. Internal content (positioning, competitive briefs, sales
|
|
# playbooks, PMM/press drip, draft campaigns) lives in Molecule-AI/internal —
|
|
# this public monorepo must never re-acquire those paths. CEO directive
|
|
# 2026-04-23 after a fleet-wide audit found 79 internal files leaked here.
|
|
#
|
|
# Failure mode without this gate: agents (PMM, Research, DevRel, Sales) drop
|
|
# briefs into the easiest path their cwd resolves to (root /research,
|
|
# /marketing, /docs/marketing) and gitignore alone won't catch a `git add -f`
|
|
# or a stale gitignore line. This workflow is the mechanical backstop.
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened]
|
|
push:
|
|
branches: [main, staging]
|
|
|
|
jobs:
|
|
check:
|
|
name: Block forbidden paths
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 2 # need previous commit to diff against on push events
|
|
|
|
- name: Refuse if forbidden paths appear
|
|
run: |
|
|
# Paths that must NEVER live in the public monorepo. Add to this
|
|
# list narrowly — broader patterns belong in .gitignore so day-to-day
|
|
# docs work isn't accidentally blocked.
|
|
FORBIDDEN_PATTERNS=(
|
|
"^research/"
|
|
"^marketing/"
|
|
"^docs/marketing/"
|
|
"^comment-[0-9]+\.json$"
|
|
"^test-pmm.*\.(txt|md)$"
|
|
"^tick-reflections.*\.(txt|md)$"
|
|
".*-temp\.(md|txt)$"
|
|
)
|
|
|
|
# Determine the diff base.
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
BASE="${{ github.event.pull_request.base.sha }}"
|
|
HEAD="${{ github.event.pull_request.head.sha }}"
|
|
else
|
|
BASE="${{ github.event.before }}"
|
|
HEAD="${{ github.event.after }}"
|
|
fi
|
|
|
|
# Files added or modified in this change.
|
|
if [ -z "$BASE" ] || echo "$BASE" | grep -qE '^0+$'; then
|
|
# New branch / no previous SHA — check entire tree.
|
|
CHANGED=$(git ls-tree -r --name-only HEAD)
|
|
else
|
|
CHANGED=$(git diff --name-only --diff-filter=AM "$BASE" "$HEAD")
|
|
fi
|
|
|
|
if [ -z "$CHANGED" ]; then
|
|
echo "No changed files to inspect."
|
|
exit 0
|
|
fi
|
|
|
|
OFFENDING=""
|
|
for path in $CHANGED; do
|
|
for pattern in "${FORBIDDEN_PATTERNS[@]}"; do
|
|
if echo "$path" | grep -qE "$pattern"; then
|
|
OFFENDING="${OFFENDING}${path} (matched: ${pattern})\n"
|
|
break
|
|
fi
|
|
done
|
|
done
|
|
|
|
if [ -n "$OFFENDING" ]; then
|
|
echo "::error::Forbidden internal-flavored paths detected:"
|
|
printf "$OFFENDING"
|
|
echo ""
|
|
echo "These paths belong in Molecule-AI/internal, not this public repo."
|
|
echo "See docs/internal-content-policy.md for canonical locations."
|
|
echo ""
|
|
echo "If your file is genuinely public-facing (e.g. a blog post"
|
|
echo "ready to ship), use one of these alternatives instead:"
|
|
echo " • Public-bound blog posts: docs/blog/<slug>.md"
|
|
echo " • Public-bound tutorials: docs/tutorials/<slug>.md"
|
|
echo " • Public devrel content: docs/devrel/<slug>.md"
|
|
echo ""
|
|
echo "If you legitimately need to add a new top-level path that"
|
|
echo "happens to match a forbidden pattern, edit"
|
|
echo ".github/workflows/block-internal-paths.yml and update the"
|
|
echo "FORBIDDEN_PATTERNS list with reviewer signoff."
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ No forbidden paths in this change."
|