Skip to content

Commit d8ec72e

Browse files
committed
Harden eternal stack gates and policy contracts
1 parent 0e59586 commit d8ec72e

94 files changed

Lines changed: 1650 additions & 485 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/health.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: health
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
- "release/**"
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
repo-health:
19+
name: Repository Health Checks
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
24+
with:
25+
persist-credentials: false
26+
27+
- name: Set up Node
28+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
29+
with:
30+
node-version: "22"
31+
cache: ""
32+
33+
- name: Install CLI dependencies
34+
run: |
35+
sudo apt-get update
36+
sudo apt-get install -y jq fd-find ripgrep shellcheck
37+
sudo ln -sf "$(command -v fdfind)" /usr/local/bin/fd
38+
39+
- name: Validate generated rule exports
40+
run: node scripts/sync-rule-exports.mjs --check
41+
42+
- name: Hook tests
43+
run: tests/test-hooks.sh
44+
45+
- name: Workflow tool tests
46+
run: tests/test-workflow-tools.sh
47+
48+
- name: Install and rollback tests
49+
run: tests/test-install.sh
50+
51+
- name: Doctor
52+
run: scripts/doctor.sh --jobs 4

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ coverage/
1515
plans/
1616
docs/plans/
1717
docs/research/
18+
# Local privacy overlay is intentionally ignored without hiding all .eternal/ state.
19+
.eternal/privacy-banned-tokens.local
20+
rules-manifest.local.json
1821

1922
# Never commit private Claude runtime data.
2023
settings.local.json

CHANGELOG.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
1818

1919
### Deprecated
2020

21+
## v0.5.2
22+
23+
2026-06-16
24+
25+
### Added
26+
27+
- `.github/workflows/health.yml` — CI health workflow for rule export sync, hook tests, workflow tests, install/rollback tests, and doctor.
28+
- `rules/eternal-saas/project/tcg-contract.md` — scoped TCG/card-domain contract rule module and generated Cursor export.
29+
30+
### Changed
31+
32+
- `scripts/sync-rule-exports.mjs` and `scripts/init-project-rules.sh` — manifest-driven rule sync now validates profile membership, generated Cursor exports, privacy overlays, and install-time Cursor checksums.
33+
- `rules/eternal-saas/*` — rule host metadata now reflects Claude and Cursor support without claiming unsupported Codex nested context output.
34+
- `skills/bundled/stripe-best-practices` — hardens Stripe guidance from advisory wording to explicit policy gates for API versions, payment-surface selection, test/migration expectations, and Connect settlement/dispute behavior.
35+
36+
### Fixed
37+
38+
- `scripts/install.sh` — validate source install inputs before any non-dry-run mutation.
39+
- `hooks/cc-stop-verifier.sh`, `hooks/cc-pretooluse-guard.sh`, and `scripts/code-health-ledger-check.mjs` — close enforcement gaps for invalid Stop JSON, live hook writes, and prompt-only code-health audits.
40+
- `scripts/update-check.mjs`, `scripts/skill-contract-check.mjs`, `scripts/tool-stack-check.mjs`, and `scripts/doctor.sh` — harden update trust, bundled skill contracts, pinned tool install specs, ShellCheck, privacy scanning, and rule export drift detection.
41+
42+
### Security
43+
44+
- `rules-manifest.json` and `scripts/doctor.sh` — remove tracked private project literals from the privacy gate and support gitignored local banned-token overlays with redacted diagnostics.
45+
2146
## v0.5.1
2247

2348
2026-06-11
@@ -53,14 +78,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
5378
- `templates/AGENTS.global.md` — portable ~32-line cross-host agent baseline for Codex startup.
5479
- `templates/AGENTS.override.codex.md` — Codex-specific startup deltas (no slash commands, no hooks, byte budget, skills path).
5580
- `docs/rules.md` — cross-host rules reference: module catalog, host activation per tool, install and drift-check commands.
56-
- `docs/adr/0003-cross-host-rule-stack.md` — decision record for the Exodia cross-host rule architecture.
81+
- `docs/adr/0003-exodia-cross-host-rules.md` — decision record for the Exodia cross-host rule architecture.
5782
- Codex byte gate in `scripts/doctor.sh` — warns when `~/.codex/AGENTS.md` exceeds 75 % of the configured `project_doc_max_bytes` limit.
5883
- Manifest assertions in `scripts/doctor.sh` — validates `rules-manifest.json` schema version, `bannedTokens` non-empty, and `rules/eternal-saas/global/` module count.
5984
- Rollback now restores `rules/eternal-saas` global digest and backed-up Codex startup files (`AGENTS.md`, `AGENTS.override.md`).
6085
- `scripts/lib/skill-lists.sh` now includes `init-project-rules.sh` in `INSTALL_SCRIPTS` so it deploys to both Claude and Codex homes.
6186
- Prompt router extended: "prune AGENTS/claude/rules", "rule bloat", "AGENTS.md/CLAUDE.md too long", "trim AGENTS/CLAUDE.md", and "startup file/context too long" prompts now route to `etrnl-ops-agent-files`. Three new skill-triggering fixture cases added.
62-
- Six project pilots with the eternal-saas pack: core-suite, agency-tbd, tcg-collector, mimo-finance, vivaz-website, and sbcc-portal — each with project-specific `local-overrides.md`, pruned `AGENTS.md`, and removed old flat rule files.
63-
- sbcc-portal `.gitignore` updated to track `.claude/rules/` while keeping local session state ignored.
87+
- Six private project pilots with the eternal-saas pack, each with project-specific `local-overrides.md`, pruned `AGENTS.md`, and removed old flat rule files.
88+
- One private pilot `.gitignore` updated to track `.claude/rules/` while keeping local session state ignored.
6489

6590
### Changed
6691

@@ -73,7 +98,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
7398

7499
### Fixed
75100

76-
- `scripts/plan-readiness-check.mjs` no longer flags hyphenated proper names such as the `agency-tbd` repo as a `TBD` placeholder; standalone `TBD` markers still fail (regression tests in `tests/test-workflow-tools.sh`).
101+
- `scripts/plan-readiness-check.mjs` no longer flags hyphenated proper names such as the `example-agency` repo as a `TBD` placeholder; standalone `TBD` markers still fail (regression tests in `tests/test-workflow-tools.sh`).
77102
- `scripts/update-check.mjs` now correctly marks `sync-rule-exports.mjs` as source-only (not installed) to prevent false drift failures.
78103
- `scripts/update-check.mjs` renamed map includes `doctor.sh → doctor-etrnl.sh` to suppress stale-scripts drift false positives.
79104

@@ -94,4 +119,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
94119
### Security
95120

96121
- Public repository boundary: no private identity, credentials, transcripts, or local planning artifacts in tracked files.
97-

CREDITS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ Eternal Stack is designed as a complete skill family. Policy, review, simplifica
2828
| `better-auth`, `tenant-isolation-patterns`, `money-vo-discipline` | Auth, tenancy, and money discipline | Community / upstream skill bundles |
2929
| `stripe-best-practices`, `abacatepay-integration` | Payments review | Community / upstream skill bundles |
3030
| `ci-cd` | CI helper scripts referenced by `/etrnl-dev-ci` | Community skill bundle |
31-
| `domain-*`, `i18n-localization`, and related domain skills | Domain-specific review gates | Community / upstream skill bundles |
31+
| `domain-cli`, `domain-cloud-native`, `domain-embedded`, `domain-fintech`, `domain-iot`, `domain-ml`, `domain-web` | Domain-specific review gates | Community / upstream skill bundles |
32+
| `prisma-expert` | Prisma schema and query review | Community / upstream skill bundle |
33+
| `i18n-localization` | Locale and translation review | Community / upstream skill bundle |
3234

3335
The full inventory and routing notes live in [docs/skills.md](docs/skills.md).
3436

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ tests/test-hooks.sh
5353

5454
**Hooks** — enforcement at tool boundaries. Full catalog and lifecycle wiring: [docs/hooks.md](docs/hooks.md). Pretool and stop rules: [docs/guards.md](docs/guards.md). Regression: [tests/test-hooks.sh](tests/test-hooks.sh).
5555

56-
**Skills** — repeatable workflows as `/etrnl-*` commands, grouped by namespace (`dev`, `audit`, `ops`, `comm`). Inventory: [docs/skills.md](docs/skills.md).
56+
**Skills** — repeatable workflows as `/etrnl-*` commands, grouped by namespace (`dev`, `audit`, `ops`, `comm`). Bundled domain skills include `domain-cli`, `domain-cloud-native`, `domain-embedded`, `domain-fintech`, `domain-iot`, `domain-ml`, and `domain-web`. Inventory: [docs/skills.md](docs/skills.md).
5757

5858
**Scripts** — deterministic helpers for ledgers, browser QA, workflow health, code-health inventory, deep-audit validation, and release hygiene.
5959

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.1
1+
0.5.2

commands/email-triage.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
description: Run VIVAZ email Inbox Zero triage for one account, then open the action queue.
2+
description: Run managed email Inbox Zero triage for one account, then open the action queue.
33
argument-hint: <account-id>
44
allowed-tools: Bash
55
---
@@ -8,41 +8,41 @@ Account argument from the slash command: `$ARGUMENTS`
88

99
Treat the argument as the account id. If it is empty, ask the repository owner for the account id and stop.
1010

11-
Do not handwrite Gmail commands. Do not send email. Do not mutate Gmail outside the VIVAZ email runtime.
12-
Do not run `vivaz-email triage run` for this slash command. That is a dry classification path and does not clear INBOX.
11+
Do not handwrite Gmail commands. Do not send email. Do not mutate Gmail outside the managed email runtime.
12+
Do not run `etrnl-email triage run` for this slash command. That is a dry classification path and does not clear INBOX.
1313

1414
Phase 1 is Inbox Zero. Triage every email in INBOX, archive known bad-quality emails, label action/waiting/manual-review items, remove them from INBOX, and provider-verify INBOX is zero:
1515

1616
```bash
17-
vivaz-email triage guarded-run --account <account-id> --max-inbox 500 --apply --require-insights
17+
etrnl-email triage guarded-run --account <account-id> --max-inbox 500 --apply --require-insights
1818
```
1919

2020
Verify the queue run before opening any queue:
2121

2222
```bash
23-
vivaz-email triage verify --latest --account <account-id>
23+
etrnl-email triage verify --latest --account <account-id>
2424
```
2525

2626
If verification does not show `inbox_zero_verified: true`, `inbox_count: 0`, and either `gmail_mutated: true` or `queue_ready_without_mutation: true`, do not show queue items. Continue Inbox Zero triage first or paste the runtime blocker.
2727

2828
If `guarded-run` exits with `TRIAGE_GUARD_ML_DISAGREED`, do not ask the repository owner whether to continue. Inspect the runtime evidence, patch deterministic triage rules/cache when appropriate, then rerun the guarded command:
2929

3030
```bash
31-
vivaz-email triage guarded-run --account <account-id> --max-inbox 500 --apply --require-insights
32-
vivaz-email triage ml-reviews --latest --account <account-id> --limit 20
33-
vivaz-email triage report --latest --account <account-id> --include-failures --format markdown
31+
etrnl-email triage guarded-run --account <account-id> --max-inbox 500 --apply --require-insights
32+
etrnl-email triage ml-reviews --latest --account <account-id> --limit 20
33+
etrnl-email triage report --latest --account <account-id> --include-failures --format markdown
3434
```
3535

3636
Phase 2 starts only after Inbox Zero is verified. Use the queue run id emitted by the runtime, then show exactly one action/reply queue item:
3737

3838
```bash
39-
vivaz-email triage queue --run-id <run-id> --mode reply --format markdown --next
39+
etrnl-email triage queue --run-id <run-id> --mode reply --format markdown --next
4040
```
4141

4242
If the queue item shows a proposed reply with a draft id, run the outgoing reply checker before asking the repository owner to approve or send it:
4343

4444
```bash
45-
vivaz-email drafts check --draft-id <draft-id>
45+
etrnl-email drafts check --draft-id <draft-id>
4646
```
4747

4848
If the checker returns any issue, stop and surface the failed draft check with the exact issue list. Do not improvise manual rewrites, and do not ask the repository owner to approve or send a failed draft until the runtime provides a checked replacement draft.

docs/adr/0003-exodia-cross-host-rules.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ date: 2026-06-10
77

88
## Context
99

10-
Claude Code, Codex, and Cursor each provide native agent-context surfaces (`.claude/rules/` with `paths:` frontmatter, `AGENTS.md` nesting, and `.mdc` with `globs`), but the rule content is currently authored separately for each project. This creates drift, duplication, and inconsistent enforcement surfaces across repos.
10+
Claude Code, Codex, and Cursor each provide native agent-context surfaces (`.claude/rules/` with `paths:` frontmatter, global `AGENTS.md` startup context, and `.mdc` with `globs`), but the rule content is currently authored separately for each project. This creates drift, duplication, and inconsistent enforcement surfaces across repos.
1111

1212
Host features verified on 2026-06-10:
1313
- **Claude Code** natively loads `.claude/rules/` and `~/.claude/rules/` with `paths:` frontmatter scoping; no hooks needed.
14-
- **Codex** reads `~/.codex/AGENTS.md` and `AGENTS.override.md`; nested `AGENTS.md` files are its only depth mechanism; no glob or import syntax.
14+
- **Codex** reads `~/.codex/AGENTS.md` and `AGENTS.override.md`; this repo installs the global startup digest and does not install project-depth rule modules for Codex.
1515
- **Cursor** `.mdc` files with `globs`, `description`, and `alwaysApply` are native; Cursor has no user-level rules directory (settings UI only).
1616

1717
`scripts/install.sh` already syncs `rules/etrnl` to `~/.claude/rules/etrnl` with an atomic tmp/old swap and implements `ETRNL_INSTALL_STARTUP` gating for startup files. The bundled skill family already publishes Eternal-stack patterns publicly (`money-vo-discipline`, `abacatepay-integration`, `eternal-best-practices`).
@@ -24,11 +24,11 @@ This record is ADR 0003. ADR 0002 is taken by `etrnl-state-and-compact-handoff`.
2424

2525
### 2. Privacy boundary
2626

27-
The `eternal-saas` rule pack ships publicly. Excluded from tracked rule files: client business names, account facts, credentials, transcripts, and personal identity. Client-repo rollout lists stay in local gitignored planning paths. Enforcement: `rules-manifest.json` carries `privacy.bannedTokens`; `sync-rule-exports.mjs --check` fails when a tracked rule file contains one.
27+
The `eternal-saas` rule pack ships publicly. Excluded from tracked rule files: client business names, account facts, credentials, transcripts, and personal identity. Client-repo rollout lists stay in local gitignored planning paths. Enforcement: `rules-manifest.json` carries generic privacy sentinel tokens plus optional untracked local token files; `sync-rule-exports.mjs --check` fails when a tracked rule file contains one.
2828

29-
### 3. Codex scoped depth via nested AGENTS.md
29+
### 3. Codex uses the startup digest
3030

31-
Each rule module may declare `codexNested: <relative-dir>`; `sync-rule-exports.mjs` emits a nested `AGENTS.md` for declared modules; undeclared modules ride the root digest only. No import syntax exists in Codex — `@` imports are never used in Codex files.
31+
The project rule pack installs to Claude Code and Cursor project surfaces. Codex receives the shared baseline through `~/.codex/AGENTS.md` and `AGENTS.override.md`; no nested project `AGENTS.md` files are generated by `sync-rule-exports.mjs` or `init-project-rules.sh`.
3232

3333
### 4. Byte budget is read, not assumed
3434

@@ -48,7 +48,7 @@ All project-pack installs use file copies. Symlinks break for other clones, CI,
4848

4949
## Consequences
5050

51-
- One source of truth for rule content; Claude `.claude/rules/`, Cursor `.mdc`, and Codex `AGENTS.md` files are generated or installed from the same module.
51+
- One source of truth for project rule content; Claude `.claude/rules/` and Cursor `.mdc` files are generated or installed from the same module. Codex receives the global baseline through startup files.
5252
- `sync-rule-exports.mjs --check` in the test suite prevents host-twin drift and banned-token leaks.
5353
- The byte-gate in `doctor.sh` keeps Codex context under the effective limit; the explicit fallback prevents silent overflow.
5454
- Checksum-tracked installs let pilot repos self-classify drift without re-running install.

docs/eternal-stack-coverage.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ Status key: `done` means implemented in this repo; `live-gated` means intentiona
2727
Eternal Stack is a bundled skill family: `etrnl-*` orchestration from this repo plus policy, review, and domain skills that install on the host and are routed by hooks and workflows. See `docs/skills.md` for the full inventory. Representative bundled skills:
2828

2929
- `eternal-best-practices`
30-
- `domain-*`
30+
- `domain-cli`
31+
- `domain-cloud-native`
32+
- `domain-embedded`
33+
- `domain-fintech`
34+
- `domain-iot`
35+
- `domain-ml`
36+
- `domain-web`
3137
- `better-auth`
3238
- `tenant-isolation-patterns`
3339
- `money-vo-discipline`

docs/health-stack.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ node scripts/update-check.mjs --explain
126126
scripts/post-upgrade-canary.sh
127127
```
128128

129+
- `.github/workflows/health.yml` runs the repository health pipeline in GitHub Actions on every pull request, on pushes to `main`, and on pushes to `release/**` branches. The workflow validates generated rule exports, then runs `tests/test-hooks.sh`, `tests/test-workflow-tools.sh`, `tests/test-install.sh`, and `scripts/doctor.sh --jobs 4`.
130+
- The workflow is the hosted counterpart to the Required Gates block above: `sync-rule-exports.mjs --check` covers generated rule drift, the hook/workflow/install suites cover runtime behavior and rollback safety, and `scripts/doctor.sh --jobs 4` replays the aggregated syntax, ShellCheck, manifest, privacy, documentation, and heavy-suite health checks.
129131
- `scripts/workflow-health.mjs` reads run ledgers in parallel with `ETRNL_LEDGER_READ_CONCURRENCY` (default `8`, capped at `12` for constrained systems). `workflow-health.mjs status` is the concise text surface used by SessionStart hints; `status --json` is the machine-readable surface for active run id, unfinished work, missing artifacts, browser/context freshness, phase/UAT state, stale run count, and the next deterministic action. Use `workflow-health.mjs doctor --strict` or `ETRNL_WORKFLOW_HEALTH_STRICT=1` when live runtime findings must fail closed instead of remaining diagnostic.
130132
- `tool-effectiveness.mjs` summarizes sanitized local tool events into deterministic `keep`, `enforce`, `repo-specific`, `remove-watch`, or `insufficient-data` verdicts. It reads hook tool-signal state, optional local event artifacts, and explicit Codex imports; it rejects raw prompts, transcript text, secrets, private transcript paths, and tracked private project names. Use the seven-day `summarize` command above to revisit CodeGraph, Beads, and stolen hook patterns without manual log reading.
131133
- `etrnl-state.mjs` is the canonical local state helper for compact lifecycle and small workflow events. It writes append-only JSONL under `~/.claude/etrnl/state`, rebuilds compact handoff views, rejects raw prompts/transcripts/private paths/secrets before append, and exposes `compact-handoff`, `stop-status`, `doctor`, `bead-link`, and `bead-prime-audit`. Hook hot paths may use bounded state appends and queries only.

0 commit comments

Comments
 (0)