Compare commits

..

33 Commits

Author SHA1 Message Date
gaurav0107
7145ca9dfe fix(hooks): address coderabbit review — use lstatSync for symlink paths
CodeRabbit major on PR #1898: fs.statSync follows symlinks, so a dangling
protected symlink (e.g. .eslintrc.js pointing at a missing target) would
throw ENOENT and be treated as absent — letting an agent "replace" the
symlink and bypass the protection.

Swap statSync for lstatSync. lstat reports the link node itself regardless
of whether its target exists, so protected entries that happen to be
symlinks stay blocked. ENOENT handling is unchanged: only a genuinely
missing path (no link, no file, no directory) counts as absent.

Add a regression test that creates a dangling symlink at .eslintrc.js and
verifies the hook still blocks Write. Skips cleanly on platforms/sandboxes
that disallow symlink creation (EPERM/EACCES).
2026-05-15 01:09:43 +05:30
gaurav0107
a8fe098c88 fix(hooks): address greptile review — use statSync for true fail-closed
Greptile P1 on PR #1898: fs.existsSync internally catches all errors and
returns false, so the previous try/catch around it was dead code and the
stated "fail-closed on EACCES" semantics weren't actually delivered. A
file under a directory with no execute permission would read as absent
and bypass the guard.

Swap to fs.statSync with explicit ENOENT detection. Only ENOENT flips
exists to false; every other error code (EACCES, EPERM, ELOOP, etc.)
leaves exists=true so the modification guard is never silently weakened.

Add a new test "allows first-time creation when the parent directory
does not exist yet" that exercises the ENOENT path via a non-existent
parent dir — pins the happy path into the regression suite.
2026-05-15 00:57:03 +05:30
gaurav0107
faa51fba11 fix(hooks): allow first-time creation of protected config files
The config-protection hook blocks Write/Edit on any basename in the
PROTECTED_FILES set, regardless of whether the file already exists. The
hook's stated purpose is to prevent agents from softening rules in an
existing config — but the same code path also blocks the legitimate
bootstrap case of scaffolding a linter config into a project that has
none.

Add an fs.existsSync check inside run(): when the basename matches a
protected entry and the file does not yet exist on disk, exit 0 and
let the Write proceed. Keep the exit-2 block for all modifications to
existing files. Stat errors (EACCES, etc.) fail closed — we treat the
path as existing so the guard is never silently weakened.

Update the existing "blocks protected config file edits" test to use a
real temp file so the BLOCK path is still exercised, and add two new
tests covering:

- first-time creation of eslint.config.mjs is allowed (exit 0, raw
  passthrough, no stderr)
- Edit against an existing .eslintrc.js is still blocked (exit 2, no
  stdout, BLOCKED message in stderr)

Fixes #1873
2026-05-15 00:30:23 +05:30
Affaan Mustafa
4423f10cfb docs: sync ECC Tools hosted output scoring (#1891) 2026-05-13 23:02:23 -04:00
Affaan Mustafa
3b12fb273f docs: sync ECC Tools hosted promotion readiness (#1890) 2026-05-13 22:39:01 -04:00
Affaan Mustafa
4fb80d8861 Sync ECC Tools status-aware depth plan roadmap (#1887) 2026-05-13 22:12:11 -04:00
Affaan Mustafa
a27831c13e Sync ECC Tools hosted status roadmap (#1886) 2026-05-13 21:49:42 -04:00
Affaan Mustafa
b24d762caa Sync ECC Tools hosted result history roadmap (#1885) 2026-05-13 21:31:08 -04:00
Affaan Mustafa
f94478e524 docs: sync roadmap after ECC-Tools hosted dispatch 2026-05-13 20:30:48 -04:00
Affaan Mustafa
6cdac19764 docs: sync roadmap after ECC-Tools depth-plan check 2026-05-13 20:10:38 -04:00
Affaan Mustafa
af3a206412 docs: sync roadmap after ECC-Tools team backlog job (#1880) 2026-05-13 19:44:49 -04:00
Affaan Mustafa
20f00c1410 docs: sync roadmap after ECC-Tools AI cost job (#1878) 2026-05-13 19:26:48 -04:00
Affaan Mustafa
e7a6f137e5 docs: sync roadmap after ECC-Tools reference-set job (#1877) 2026-05-13 19:09:35 -04:00
Affaan Mustafa
7596502092 docs: sync roadmap after ECC-Tools harness job (#1876) 2026-05-13 18:50:45 -04:00
Affaan Mustafa
c04baa8c25 docs: sync roadmap after ECC-Tools security evidence job (#1875) 2026-05-13 18:32:06 -04:00
Affaan Mustafa
9082bdedac docs: sync roadmap after ECC-Tools CI diagnostics (#1874) 2026-05-13 18:12:31 -04:00
Affaan Mustafa
3243a1c5d3 docs: sync roadmap after ECC-Tools hosted planning (#1872) 2026-05-13 12:48:50 -04:00
Affaan Mustafa
69401b28b3 docs: sync roadmap after ECC-Tools depth readiness (#1871) 2026-05-13 12:26:32 -04:00
Affaan Mustafa
9a5ed3223a docs: sync roadmap after AgentShield corpus expansion
Records AgentShield PR #82 and moves the next AgentShield roadmap slice to hosted evidence-pack workflow depth.
2026-05-13 09:04:34 -04:00
Affaan Mustafa
d844bd6bfc docs: sync roadmap after AgentShield remediation workflows
Records AgentShield PR #81 and advances the next AgentShield roadmap slice after remediation workflow phases landed.
2026-05-13 08:46:07 -04:00
Affaan Mustafa
cf54c791e4 docs: sync roadmap after AgentShield corpus recommendations
Syncs the ECC 2.0 GA roadmap after AgentShield PR #80 landed corpus accuracy recommendations.
2026-05-13 08:28:12 -04:00
Affaan Mustafa
bd4369e1d5 docs: sync roadmap after ECC-Tools PR draft tracking (#1865) 2026-05-13 08:11:09 -04:00
Affaan Mustafa
f2be190dcb docs: sync roadmap after AgentShield fingerprint hardening 2026-05-13 07:53:15 -04:00
Affaan Mustafa
2afef0f18b docs: sync roadmap after ECC-Tools hardening 2026-05-13 07:32:55 -04:00
Affaan Mustafa
967e5c6922 docs: mark JARVIS backend audit clean 2026-05-13 07:15:13 -04:00
Affaan Mustafa
2d29643dd4 docs: sync ECC 2.0 GA roadmap after hardening pass 2026-05-13 06:59:20 -04:00
Affaan Mustafa
c2762dd569 feat: add Ruby and Rails rules 2026-05-13 06:27:08 -04:00
Affaan Mustafa
cb3509ee19 docs: sync AgentShield adapter roadmap
Record AgentShield #68/#69 in the ECC GA roadmap and update the next enterprise slice.
2026-05-13 04:43:58 -04:00
Affaan Mustafa
42f04edc03 ci: gate observability on release safety evidence
Add release-safety evidence coverage to observability readiness and refresh rc.1 publication gate docs.
2026-05-13 04:14:47 -04:00
Affaan Mustafa
d4728a0d80 fix: fall back to ASCII instinct status bars
Fixes #1855
2026-05-13 02:59:58 -04:00
SeungHyun
0e169fecbc fix: harden GateGuard destructive bash tokenizer
Co-authored-by: Jamkris <dltmdgus1412@gmail.com>
2026-05-13 02:43:04 -04:00
Affaan Mustafa
b2506f82f6 docs: sync AgentShield evidence-pack roadmap (#1854) 2026-05-13 02:22:05 -04:00
Affaan Mustafa
f6e13ab520 docs: record post-hardening rc1 release evidence (#1852) 2026-05-13 01:32:58 -04:00
23 changed files with 1101 additions and 109 deletions

View File

@@ -16,12 +16,14 @@ so the live execution truth is split across:
As of 2026-05-13:
- Public GitHub queues are clean across `affaan-m/everything-claude-code`,
- GitHub queues are clean across `affaan-m/everything-claude-code`,
`affaan-m/agentshield`, `affaan-m/JARVIS`, `ECC-Tools/ECC-Tools`, and
`ECC-Tools/ECC-website`.
- Public GitHub discussions are also clean across those tracked repos:
the latest GraphQL sweep found only closed discussions on the trunk
discussion surface, and satellite discussion surfaces are disabled or empty.
`ECC-Tools/ECC-website`: the latest sweep found 0 open PRs and 0 open
issues across all five repos.
- GitHub discussions are also clean across those tracked repos:
the latest GraphQL sweep found 52 total trunk discussions with 0 open,
and 0 total/open discussions on AgentShield, JARVIS, ECC-Tools, and the
ECC-Tools website.
- The final open public GitHub issue, #1314, was closed as a non-actionable
external badge/listing notification with a courtesy comment.
- Linear issue creation for this project was re-tested after GitHub cleanup and
@@ -30,7 +32,7 @@ As of 2026-05-13:
Linear project status updates remain the active tracking surfaces until the
workspace is upgraded or issue capacity is freed.
- `npm run harness:audit -- --format json` reports 70/70 on current `main`.
- `npm run observability:ready` reports 18/18 readiness on current `main`,
- `npm run observability:ready` reports 21/21 readiness on current `main`,
including the GitHub/Linear/handoff/roadmap progress-sync contract.
- PR #1846 merged as `797f283036904128bb1b348ae62019eb9f08cf39` and made
npm registry signature verification a durable workflow-security gate:
@@ -39,6 +41,147 @@ As of 2026-05-13:
`docs/security/supply-chain-incident-response.md`, plus a workflow-security
validator rule blocking `pull_request_target` workflows from restoring or
saving shared dependency caches.
- PR #1850 merged as `248673271455e9dc85b8add2a6ab76107b718639` and removed
shell access from read-only analyzer agents and zh-CN copies, reducing
AgentShield high findings on that surface without changing operator agents.
- PR #1851 merged as `209abd403b7eaa968c6d4fa67be82e04b55706d6` and made
`persist-credentials: false` mandatory for `actions/checkout` in workflows
with write permissions.
- PR #1860 merged as `c2762dd5691a33aaa7f84a0a4901a5bab7980fc8` and closed
#1859 by adding the Ruby/Rails language pack surface, install aliases,
selective-install components, and focused install-manifest executor tests.
- AgentShield PR #78 merged as `1b19a985d6ae1346244089a78806a7d5eaaf270e`
and hardened the release workflow with `persist-credentials: false` plus
`npm ci --ignore-scripts` in the write/id-token release path.
- AgentShield PR #79 merged as `86a823c5f2c35ee97e6ecf6f99e9ac301d54119a`
and moved baseline/watch/remediation fingerprints to a shared hashed
evidence fingerprint helper. New baselines omit raw finding evidence while
older raw-evidence baselines remain comparable.
- AgentShield PR #80 merged as `8ed379d1de067b25640ac6273aa4d9f8e6735d43`
and added prioritized corpus accuracy recommendations to failed corpus gates,
mapping misses by category, missing rule, and config ID so enterprise
scanner-regression work has an actionable improvement plan.
- AgentShield PR #81 merged as `6583884e74ba2e896942113e1ce3146230e6fb76`
and added ordered remediation workflow phases to remediation plans, routing
safe auto-fixes, manual review, and verification through stable finding
fingerprints without copying raw evidence.
- AgentShield PR #82 merged as `51336ba074ad5e9fed2c0aa3237422be22147e76`
and expanded the built-in attack corpus with an env proxy hijack scenario
covering proxy/runtime mutation, env-token exfiltration, DNS exfiltration,
credential-store access, and clipboard access.
- JARVIS PR #13 merged as `127efabbfb5033ae53d7a53e1546aa3c33d6f962`
and hardened CI/deploy workflows with npm registry signature verification,
disabled persisted checkout credentials in write-permission jobs, and pinned
the Vercel CLI install instead of using `latest`.
- ECC-Tools PR #53 merged as `99018e943d03f024de8c9d278c91f66393d4f1ee`
and added npm registry signature verification before the existing production
dependency audit in CI.
- ECC-Tools PR #54 merged as `05df89721f49c1e19d8502c545e26f5694806998`
and made `/ecc-tools followups sync-linear` track copy-ready PR drafts in
the Linear/project backlog when `open-pr-drafts` is not used, preserving
useful stale-PR salvage work without opening extra PR shells.
- ECC-Tools PR #55 merged as `5d8c112cce4794cfa089d5b0ea661ba87a178be1`
and added analysis-depth readiness to `/ecc-tools analyze` comments,
separating commit-history-only repos from evidence-backed and deep-ready repos
using CI/CD, security, harness, reference/eval, AI routing/cost-control, and
team handoff evidence.
- ECC-Tools PR #56 merged as `5b729c88641eafe80f65364bab3fc74d0270f57b`
and added the authenticated `/api/analysis/depth-plan` contract that maps
analysis-depth readiness into concrete hosted jobs for CI diagnostics,
security evidence review, harness compatibility, reference-set evaluation,
AI routing/cost review, and team backlog routing.
- ECC-Tools PR #57 merged as `4cc61112a4cc9feec7b07af09321f360e34af6a4`
and added the first executable hosted analysis job:
`/api/analysis/jobs/ci-diagnostics` now gates on CI/CD readiness, inspects
workflow/test-runner/failure-evidence artifacts, returns CI hardening
findings and next actions, and charges usage only after successful execution.
- ECC-Tools PR #58 merged as `ce09dd8d9b46f65c6b88dc4f48cfb6b6227ae0bf`
and added the second executable hosted analysis job:
`/api/analysis/jobs/security-evidence-review` now gates on security-evidence
readiness, inspects capped AgentShield evidence-pack, policy, baseline,
SBOM, SARIF, and security-scan artifacts, returns supply-chain evidence
findings and next actions, and charges usage only after successful execution.
- ECC-Tools PR #59 merged as `505b372dbd8f75f996d9e2ed079effd30cec5ba5`
and added the third executable hosted analysis job:
`/api/analysis/jobs/harness-compatibility-audit` now gates on harness-config
readiness, inspects capped Claude, Codex, OpenCode, MCP, plugin, and
cross-harness documentation artifacts, excludes local secret-bearing config
paths from fetches, returns portability findings and next actions, and
charges usage only after successful execution.
- ECC-Tools PR #60 merged as `b75e0a49ba5672b1ec9a2a4880ddcfa2d07dc557`
and added the fourth executable hosted analysis job:
`/api/analysis/jobs/reference-set-evaluation` now gates on reference-evidence
readiness, evaluates analyzer corpus, RAG/evaluator, PR salvage/review,
harness, security, and CI failure-mode evidence, excludes obvious
secret-bearing fixture paths from fetches, returns reference coverage
findings and next actions, and charges usage only after successful execution.
- ECC-Tools PR #61 merged as `7b01b67cae0b80774b311cb515b7eca0aa038c65`
and added the fifth executable hosted analysis job:
`/api/analysis/jobs/ai-routing-cost-review` now gates on AI routing/cost
readiness, evaluates model routing, token budget, usage-limit, rate-limit,
billing/entitlement, cost-regression, and cost-policy evidence, excludes
obvious secret-bearing paths from fetches, returns cost-control findings and
next actions, and charges usage only after successful execution.
- ECC-Tools PR #62 merged as `781d6733e56f7556edb43fb96bdfb00b1f0a3aa6`
and added the sixth executable hosted analysis job:
`/api/analysis/jobs/team-backlog-routing` now gates on team handoff/project
tracking readiness, evaluates roadmap, runbook, handoff, release-plan,
issue-template, ownership, project-tracker, backlog, and follow-up evidence,
excludes obvious secret-bearing paths from fetches, returns team-routing
findings and next actions, and charges usage only after successful execution.
- ECC-Tools PR #63 merged as `fb9e4c5ceb9ccde50da74c7a69c3fa4bd321fc07`
and made the hosted execution plan operator-visible on queued PR analysis:
the queue now publishes a non-blocking `ECC Tools / Hosted Depth Plan`
check-run on the PR head SHA with ready/blocked hosted executor commands
and next action text, while keeping check-run publication best-effort so
bundle generation and analysis comments are not blocked.
- ECC-Tools PR #64 merged as `72020ef94db94840812977ea7ac37e9344036668`
and added PR-facing hosted job dispatch controls:
`/ecc-tools analyze --job ...` comments now queue hosted jobs against the
PR head SHA, execute them through the existing hosted readiness/evidence
gates, post artifacts/findings/next actions back to the PR, and scope
idempotency keys by job id so hosted jobs do not collide with bundle
analysis.
- ECC-Tools PR #65 merged as `bacd4adf6a3a629e8d403865456d15f127baaf4e`
and added hosted job result history/check-run summaries:
queued hosted jobs now cache both the latest result and immutable run records
for completed or blocked runs, then publish a non-blocking per-job check-run
on the PR head SHA with artifacts, findings, readiness blockers, and next
actions.
- ECC-Tools PR #66 merged as `4e1db48252d068ea5dcf4308b0bc11b0dfe0c9ce`
and added a read-only hosted status command:
`/ecc-tools analyze --job status` now reads the #65 latest-result cache for
the current PR head and posts a compact completed/blocked/not-run table with
the next hosted job command, without queueing work or billing usage.
- ECC-Tools PR #67 merged as `f20e6bec2b0bf49e4cc36e08b7285c795973b73d`
and made the hosted depth-plan check-run status-aware:
queued PR analysis now reads the #65/#66 latest-result cache when publishing
`ECC Tools / Hosted Depth Plan`, includes the latest hosted run status in
the plan table, and recommends the next unrun ready job before reruns.
- ECC-Tools PR #68 merged as `2cde524b5ef8f34ab7bb1af973248fe4be4359f8`
and added deterministic hosted promotion readiness:
opened/synchronized PRs now publish a non-blocking
`ECC Tools / Hosted Promotion Readiness` check-run that compares changed
files against the checked-in evaluator/RAG corpus, warns on missing
hosted-job promotion evidence, and can be disabled with
`PR_HOSTED_PROMOTION_READINESS_CHECK_MODE=off`.
- ECC-Tools PR #69 merged as `d0112dac7cef807ae27def41f057682ef0772cce`
and extended hosted promotion readiness with deterministic output scoring:
the check now reads cached completed hosted job results for the current PR
head, scores their artifacts and findings against evaluator/RAG corpus
expectations, and treats matching hosted artifacts as promotion evidence
before reporting a gap.
- Handoff `ecc-supply-chain-audit-20260513-0645.md` under
`~/.cluster-swarm/handoffs/`
records the May 13 supply-chain sweep: no active lockfile/manifest hit for
TanStack/Mini Shai-Hulud indicators; npm audit/signature checks clean across
active npm lockfiles; `cargo audit` clean for `ecc2`; trunk `pip-audit`
clean; JARVIS backend pinned-graph Python audit clean under the supported
Python 3.12 target.
- PR #1861 validation refreshed `node scripts/harness-audit.js --format json`
at 70/70 and `npm run observability:ready` at 21/21.
- PR #1862 updated this roadmap after the JARVIS backend Python audit was
re-run against the supported Python 3.12 pinned graph.
- `docs/architecture/harness-adapter-compliance.md` maps Claude Code, Codex,
OpenCode, Cursor, Gemini, Zed-adjacent, dmux, Orca, Superset, Ghast, and
terminal-only support to install paths, verification commands, and risk
@@ -61,8 +204,12 @@ As of 2026-05-13:
release-readiness evidence refresh: 70/70 harness audit, adapter compliance
PASS, 16/16 observability readiness, 2376/2376 root Node tests, markdownlint,
release-surface and npm publish-surface tests, and 462/462 `ecc2` Rust tests.
- After #1848, `node tests/run-all.js` reports 2377/2377 and the current
observability gate reports 18/18.
- `docs/releases/2.0.0-rc.1/publication-evidence-2026-05-13-post-hardening.md`
records the post-hardening release-readiness refresh after PR #1850 and
PR #1851: 70/70 harness audit, adapter compliance PASS, 18/18 observability
readiness, 2380/2380 root Node tests, markdownlint, release-surface and
npm publish-surface tests, 462/462 `ecc2` Rust tests, npm audit/signature
checks, Rust advisory audit, and TanStack/Mini Shai-Hulud IOC checks.
- A detached clean worktree at
`bfacf37715b39655cbc2c48f12f2a35c67cb0253` verified Claude plugin tag
dry-run without `--force`, local marketplace discovery, temp-home local
@@ -121,6 +268,22 @@ As of 2026-05-13:
CLI command with severity filtering, JSON metadata output, README/API docs,
rebuilt CLI bundle, local TDD coverage, and green remote action/self-scan/Node
verification.
- AgentShield PR #65 pinned workflow actions for release/security CI hardening.
- AgentShield PR #66 disabled cache use in the release publish job so release
publication does not depend on mutable restored build state.
- AgentShield PR #67 added the first portable enterprise evidence-pack bundle:
`agentshield scan --evidence-pack <dir>` writes deterministic manifest,
README, JSON, HTML, SARIF, policy-evaluation, baseline-comparison, and
supply-chain artifacts with default redaction and `not-run` markers for
optional policy/baseline evidence.
- AgentShield PR #68 hardened evidence-pack redaction for enterprise credential
families including GitHub fine-grained PATs, GitLab PATs, npm tokens, Linear
API keys, Stripe keys, Google API keys, Hugging Face tokens, Vercel tokens,
AWS access key IDs, and JWT-shaped credentials.
- AgentShield PR #69 added the deterministic harness adapter registry. Scan
reports now surface local marker evidence for Claude Code, OpenCode, Codex,
Gemini, dmux, generic terminal agents, and project-local templates in JSON,
markdown, terminal, and HTML outputs.
- AgentShield PDF-export decision: defer a native PDF writer for now. The
self-contained HTML executive report remains the exportable buyer artifact
and can be printed to PDF when needed; native PDF generation should wait for
@@ -183,6 +346,74 @@ As of 2026-05-13:
quality, AgentShield policy exceptions, skill-quality evidence,
deep-analyzer evidence, and RAG/evaluator comparison evidence, with each
scenario exercising missing-evidence and evidence-backed diffs.
- ECC-Tools PR #41 hardened supply-chain dependencies.
- ECC-Tools PR #42 added AgentShield evidence-pack gap prediction and routed
missing policy/baseline/allowlist/suppression/supply-chain evidence into the
PR-risk taxonomy, follow-up drafts, and Linear-ready backlog table.
- ECC-Tools PR #43 recognized the concrete AgentShield #67 evidence-pack
artifact contract so canonical bundle files now satisfy the taxonomy and
generated follow-up PRs point maintainers at
`agentshield scan --evidence-pack <dir>`.
- ECC-Tools PR #55 added the first hosted/deeper-analysis readiness signal:
analysis comments now classify a repo as commit-history-only,
evidence-backed, or deep-ready before routing work into CI, AgentShield,
harness, reference-set, RAG/evaluator, AI-routing, cost-control, and
Linear/project-tracking lanes.
- ECC-Tools PR #56 turned that signal into a hosted execution-plan contract:
`/api/analysis/depth-plan` returns ready/blocked jobs and next action text
without charging analysis usage or creating bundle PRs.
- ECC-Tools PR #57 implemented the first job-specific hosted executor:
`/api/analysis/jobs/ci-diagnostics` reuses the depth-readiness gate, internal
API auth, installation ownership, repo-access billing checks, capped workflow
file reads, and usage accounting to return concrete CI hardening findings.
- ECC-Tools PR #58 implemented the second job-specific hosted executor:
`/api/analysis/jobs/security-evidence-review` applies the same hosted gates
to AgentShield evidence-pack, policy, baseline, SBOM, SARIF, and security
scanner artifacts.
- ECC-Tools PR #59 implemented the third job-specific hosted executor:
`/api/analysis/jobs/harness-compatibility-audit` applies the same hosted
gates to Claude, Codex, OpenCode, MCP, plugin, and cross-harness evidence
while avoiding local secret-bearing harness config fetches.
- ECC-Tools PR #60 implemented the fourth job-specific hosted executor:
`/api/analysis/jobs/reference-set-evaluation` applies the same hosted gates
to analyzer corpus, RAG/evaluator, PR salvage, harness, security, and CI
failure-mode reference evidence while avoiding obvious secret-bearing fixture
fetches.
- ECC-Tools PR #61 implemented the fifth job-specific hosted executor:
`/api/analysis/jobs/ai-routing-cost-review` applies the same hosted gates to
model-routing, token-budget, usage-limit, rate-limit, billing/entitlement,
cost-regression, and cost-policy evidence while avoiding obvious
secret-bearing path fetches.
- ECC-Tools PR #62 implemented the sixth job-specific hosted executor:
`/api/analysis/jobs/team-backlog-routing` applies the same hosted gates to
roadmap, runbook, handoff, release-plan, issue-template, ownership,
project-tracker, backlog, and follow-up evidence while avoiding obvious
secret-bearing path fetches.
- ECC-Tools PR #63 publishes the hosted depth-plan check-run after queued PR
analysis completes, making the six hosted executor commands visible on the
PR head SHA without turning the check into a merge blocker.
- ECC-Tools PR #64 wires those commands into the queue: maintainers can comment
`/ecc-tools analyze --job ci-diagnostics`, `security-evidence`,
`harness-compatibility`, `reference-set-evaluation`, `ai-routing-cost`, or
`team-backlog` on a PR and receive hosted job results in a PR comment.
- ECC-Tools PR #65 persists completed and blocked hosted job results to the
analysis cache for 30 days and publishes non-blocking `ECC Tools / Hosted
Job: ...` check-runs so maintainers can scan hosted outcomes from the PR
checks surface instead of rereading older comments.
- ECC-Tools PR #66 exposes the cached results from PR comments with
`/ecc-tools analyze --job status`, summarizing completed, blocked, and
not-yet-run hosted jobs for the PR head and recommending the next hosted job
command.
- ECC-Tools PR #67 feeds those cached results back into the hosted depth-plan
check-run so queued analysis recommends the next unrun ready hosted job from
cache state instead of repeating the static readiness order.
- ECC-Tools PR #68 adds the first evaluator-backed hosted promotion gate:
opened/synchronized PRs get a non-blocking Hosted Promotion Readiness
check-run that turns the evaluator/RAG corpus into warnings when changed
files match fixture scenarios without their expected evidence artifacts.
- ECC-Tools PR #69 extends that gate to score cached completed hosted job
outputs for the current PR head, so hosted artifacts can satisfy corpus
evidence expectations before the check reports a promotion gap.
- ECC PR #1803 landed the contributor Quarkus handling branch after maintainer
cleanup, current-`main` alignment, full local validation, and preservation of
the author's removal of incomplete ja-JP and zh-CN Quarkus translations.
@@ -208,7 +439,7 @@ As of 2026-05-13:
- Keep public PRs and issues below 20, with zero as the preferred release-lane
target.
- Maintain 70/70 harness audit and 16/16 observability readiness after every
- Maintain 70/70 harness audit and 21/21 observability readiness after every
GA-readiness batch.
- Do not publish release or social announcements until the GitHub release,
npm/package state, billing state, and plugin submission surfaces are verified
@@ -225,24 +456,24 @@ is not complete unless the evidence column exists and has been freshly verified.
| Prompt requirement | Required artifact or gate | Current evidence | Status |
| --- | --- | --- | --- |
| Keep public PRs below 20 | Repo-family PR recheck | 0 open PRs across the tracked public repos on 2026-05-13 after merging #1848 | Complete for this checkpoint |
| Keep public issues below 20 | Repo-family issue recheck | 0 open issues across the tracked public repos on 2026-05-13 | Complete for this checkpoint |
| Manage repository discussions | Repo-family discussion recheck | Latest trunk discussion GraphQL sweep returned closed discussions only; satellite repos remain disabled or empty | Complete for this checkpoint |
| Manage PR discussions | PR review/comment closure plus merge/close state | #1848 merged after current-head CI; no open PRs remain | Complete for this checkpoint |
| Keep public PRs below 20 | Repo-family PR recheck | 0 open PRs across `everything-claude-code`, AgentShield, JARVIS, `ECC-Tools/ECC-Tools`, and `ECC-Tools/ECC-website` on 2026-05-13 after merging ECC #1860, AgentShield #78, JARVIS #13, and ECC-Tools #53 | Complete |
| Keep public issues below 20 | Repo-family issue recheck | 0 open issues across `everything-claude-code`, AgentShield, JARVIS, `ECC-Tools/ECC-Tools`, and `ECC-Tools/ECC-website` on 2026-05-13 | Complete |
| Manage repository discussions | Repo-family discussion recheck | GraphQL sweep returned 52 total trunk discussions with 0 open; AgentShield, JARVIS, ECC-Tools, and ECC-Tools website returned 0 total/open discussions | Complete |
| Manage PR discussions | PR review/comment closure plus merge/close state | ECC #1860, AgentShield #78, JARVIS #13, and ECC-Tools #53/#54 merged after current-head CI/builds; no open tracked PRs remain | Complete |
| Salvage useful stale work | `docs/stale-pr-salvage-ledger.md` | Ledger records salvaged, superseded, skipped, and manual-review tails; #1815-#1818 added cost tracking, skill scout, frontend design guidance, code-reviewer false-positive guardrails, and the May 12 gap pass | Complete except translation/manual review tail |
| ECC 2.0 preview pack ready | Release docs, quickstart, publication readiness, release notes | `docs/releases/2.0.0-rc.1/` and readiness docs are in-tree; May 13 evidence refresh records harness, adapter, observability, Node, lint, release-surface, npm publish-surface, and Rust checks | Needs final clean-checkout release approval |
| Hermes specialized skills included safely | Hermes setup/import docs and sanitized skill surface | Hermes setup and import playbook are public; secrets stay local | Needs final release review |
| Naming and rename readiness | Naming matrix across package/plugin/docs/social surfaces | `docs/releases/2.0.0-rc.1/naming-and-publication-matrix.md` records current package, repo, Claude plugin, Codex plugin, OpenCode, and npm availability evidence | Complete for rc.1; post-rc rename remains future work |
| Claude and Codex plugin publication | Contact/submission path with required artifacts and status | Publication readiness, naming matrix, and May 12 dry-run evidence document plugin validation, clean-checkout Claude tag/install smoke, and Codex marketplace CLI shape | Needs explicit approval for real tag/push and marketplace submission |
| Articles, tweets, and announcements | X thread, LinkedIn copy, GitHub release copy, push checklist | Draft launch collateral exists under rc.1 release docs | Needs URL-backed refresh |
| AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, enterprise research roadmap | PRs #53, #55-#64 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` selects baseline drift as the first control-plane slice | Baseline-drift Action and CLI write surfaces landed; evidence-pack routing remains |
| ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus | PRs #26-#40 landed with test evidence | Needs capacity-backed Linear rollout |
| GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, and PR Review/Salvage Evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard | Partially complete |
| Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts | Local corpus complete; hosted integration remains future |
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit | Needs recurring status updates after each merge batch |
| AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, evidence-pack redaction, harness adapter registry, enterprise research roadmap, supply-chain hardened release path, CI-safe baseline fingerprints, corpus accuracy recommendations, remediation workflow phases, env proxy hijack corpus coverage | PRs #53, #55-#64, #67-#69, and #78-#82 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` now has baseline drift, evidence-pack bundle, redaction, adapter-registry, supply-chain hardening, hashed baseline fingerprints, corpus accuracy recommendation, remediation workflow, and env proxy hijack corpus slices landed | Next hosted evidence-pack workflow depth |
| ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus, analysis-depth readiness, hosted execution planning, hosted CI diagnostics, hosted security evidence review, hosted harness compatibility audit, hosted reference-set evaluation, hosted AI routing/cost review, hosted team backlog routing, hosted depth-plan check-run, PR-comment hosted job dispatch, hosted job result history/check-runs, hosted result status command, status-aware depth-plan recommendations, hosted promotion readiness, hosted promotion output scoring | PRs #26-#43 plus #53-#69 landed with test evidence, including AgentShield evidence-pack gap routing, canonical bundle recognition, supply-chain signature gates, PR draft follow-up Linear tracking, evidence-backed/deep-ready repository classification, the `/api/analysis/depth-plan` hosted job plan, `/api/analysis/jobs/ci-diagnostics`, `/api/analysis/jobs/security-evidence-review`, `/api/analysis/jobs/harness-compatibility-audit`, `/api/analysis/jobs/reference-set-evaluation`, `/api/analysis/jobs/ai-routing-cost-review`, `/api/analysis/jobs/team-backlog-routing`, the `ECC Tools / Hosted Depth Plan` check-run, `/ecc-tools analyze --job ...` PR-comment dispatch, non-blocking per-hosted-job result check-runs backed by 30-day result cache records, `/ecc-tools analyze --job status` cache lookup, cache-aware next-job recommendations in the depth-plan check-run, the `ECC Tools / Hosted Promotion Readiness` corpus-backed PR check-run, and deterministic hosted-output scoring against cached completed job artifacts/findings | Next work is retrieval/model-backed hosted promotion after deterministic output scoring |
| GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, PR Review/Salvage Evidence, and AgentShield evidence-pack evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard; #1851 added the privileged checkout credential-persistence guard; AgentShield #78, JARVIS #13, and ECC-Tools #53 applied the same hardening outside trunk | Current supply-chain gate complete; deeper hosted review features remain future |
| Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts; ECC-Tools PRs #68/#69 now turn that corpus into a deterministic PR check-run gate with cached hosted-output scoring | Deterministic hosted PR check and cached output scoring integrated; hosted retrieval remains future |
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit; this May 13 sync adds ECC #1860, AgentShield #78-#82, JARVIS #13, ECC-Tools #53-#69, resolved queue/discussion counts, and Linear project status updates through ECC-Tools #69 | Needs recurring status updates after each merge batch |
| Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below and `docs/architecture/progress-sync-contract.md` makes GitHub/Linear/handoff/roadmap sync part of the readiness gate | Active |
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout |
| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 18/18 | Complete for local gate |
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items, and ECC-Tools #54 adds copy-ready PR drafts to that backlog when draft PR shells are not opened; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout |
| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 21/21 | Complete for local gate |
| Proper release and notifications | Release tag, npm publish state, plugin state, social posts | Publication readiness gate exists with May 12 dry-run and May 13 readiness evidence | Not complete; approval/live URLs required |
## Execution Lanes And Tracking Contract
@@ -258,9 +489,9 @@ repo evidence and merge commits.
| Queue hygiene and salvage | GitHub PR/issue state, salvage ledger | Append ledger entries for any future stale closures | Every cleanup batch |
| Release and publication | rc.1 release docs, publication readiness doc | Naming matrix and plugin submission/contact checklist | Before any tag |
| Harness OS core | Audit, adapter matrix, observability docs, `ecc2/` | HUD/session-control acceptance spec | Weekly until GA |
| Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures | Hosted retrieval/check-run automation plan |
| AgentShield enterprise | AgentShield PR evidence and roadmap notes | Baseline-drift evidence-pack and backlog sync follow-up | Next implementation batch |
| ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | Capacity-backed Linear rollout | Next implementation batch |
| Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures; ECC-Tools #68 publishes the corpus as a hosted promotion readiness check-run, and #69 scores cached hosted job outputs against the same corpus | Hosted retrieval/model-backed promotion plan |
| AgentShield enterprise | AgentShield PR evidence and roadmap notes | Remediation workflow depth or corpus expansion follow-up | Next implementation batch |
| ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | ECC-Tools #53 published the supply-chain workflow hardening branch, #54 tracks copy-ready PR drafts in the Linear/project backlog, #55 classifies analysis-depth readiness, #56 exposes the hosted execution plan, #57 executes the first hosted CI diagnostics job, #58 executes the hosted security evidence review job, #59 executes the hosted harness compatibility audit, #60 executes the hosted reference-set evaluation, #61 executes the hosted AI routing/cost review, #62 executes hosted team backlog routing, #63 publishes the hosted depth-plan check-run, #64 dispatches hosted jobs from PR comments, #65 persists hosted result history/check-runs, #66 exposes hosted job status from PR comments, #67 makes depth-plan recommendations cache-aware, #68 publishes hosted promotion readiness from the evaluator/RAG corpus, and #69 scores cached hosted job outputs against that corpus; next work is retrieval/model-backed hosted promotion | Next implementation batch |
| Linear progress | Linear project status updates, `docs/architecture/progress-sync-contract.md`, and this mirror | Status update with queue/evidence/missing gates | Every significant merge batch |
The project status update should always include:
@@ -331,7 +562,7 @@ Target: 2026-06-07
Acceptance:
- Observability readiness remains 16/16 and is backed by JSONL traces, status
- Observability readiness remains 21/21 and is backed by JSONL traces, status
snapshots, risk ledger, and exportable handoff contracts.
- HUD/status model covers context, tool calls, active agents, todos, checks,
cost, risk, and queue state.
@@ -437,6 +668,9 @@ Acceptance:
- Linear sync maps deferred backlog findings to Linear issues without flooding
GitHub, creates or reuses exact-title Linear issues when configured, and
reports skipped sync when credentials or team configuration are absent.
- Linear/project backlog sync includes copy-ready PR drafts when
`/ecc-tools followups sync-linear` is used without `open-pr-drafts`, so
stale-PR salvage work remains tracked without opening extra PR shells.
- Follow-up generation caps automatic GitHub object creation and keeps overflow
findings in a copy-ready project sync backlog.
@@ -460,14 +694,26 @@ Acceptance:
## Next Engineering Slices
1. Finish the AgentShield baseline-drift control-plane slice from
1. Continue the AgentShield enterprise control-plane sequence from
`docs/architecture/agentshield-enterprise-research-roadmap.md`: PR #63
shipped the GitHub Action baseline outputs and job-summary evidence; PR #64
shipped GitHub Action baseline outputs and job-summary evidence; PR #64
shipped first-class baseline snapshot creation through
`agentshield baseline write`; the remaining work is evidence-pack routing
and ECC-Tools backlog sync integration.
2. Enable/configure the merged Linear backlog sync path after workspace issue
capacity clears or the Linear workspace is upgraded.
3. Use the ECC-Tools evaluator/RAG corpus as the promotion gate before adding
`agentshield baseline write`; PR #67 shipped the evidence-pack bundle; PR
#68 hardened evidence-pack redaction; PR #69 shipped the multi-harness
adapter registry; PR #78 hardened the release workflow for the current
supply-chain incident class; PR #79 moved baseline/watch/remediation
fingerprints to hashed evidence and stopped writing raw evidence into new
baselines; PR #80 added prioritized corpus accuracy recommendations for
failed regression gates; PR #81 added ordered remediation workflow phases;
PR #82 expanded corpus coverage for env proxy hijacks and out-of-band
exfiltration; and ECC-Tools PRs #42/#43 now route and recognize evidence
packs. The next slice is hosted evidence-pack workflow depth.
2. Plan retrieval/model-backed hosted promotion on top of the #69 deterministic
hosted output scoring contract, keeping vector/model judgment behind fixture
evaluation until the retrieval contract is stable.
3. Enable/configure the merged Linear backlog sync path after workspace issue
capacity clears or the Linear workspace is upgraded, then verify PR-draft
salvage items land in the expected project.
4. Use the ECC-Tools evaluator/RAG corpus as the promotion gate before adding
hosted retrieval, vector storage, model-backed judging, or automated
check-run promotion.

View File

@@ -35,6 +35,10 @@ operator needs.
- Progress sync: `docs/architecture/progress-sync-contract.md` defines how
GitHub, Linear, local handoffs, the repo roadmap, and `scripts/work-items.js`
stay aligned during merge batches and release-gate reviews.
- Release safety: `docs/releases/2.0.0-rc.1/publication-readiness.md`,
post-hardening evidence, supply-chain incident response, workflow-security
validation, npm pack checks, and release-surface tests must be present before
any public tag, package publish, plugin submission, or announcement action.
## Reference Pressure
@@ -71,6 +75,9 @@ later, but only after the local event model is useful enough to trust.
relying on local work-item status for a tracked repository.
7. Use ECC2 tool logs for risky operations, conflict analysis, and handoff
review before increasing autonomy.
8. Re-run the release-safety evidence checks before any public release action:
publication readiness, supply-chain incident response, workflow-security
validation, package surface, and release-surface tests.
The end-state is practical: before asking ECC to run larger multi-agent loops,
the operator can prove the system has live status, durable session traces,

View File

@@ -0,0 +1,98 @@
# ECC v2.0.0-rc.1 Publication Evidence - 2026-05-13 Post-Hardening
This is release-readiness evidence only. It does not create a GitHub release,
npm publication, plugin tag, marketplace submission, or announcement post.
## Source Commit
| Field | Evidence |
| --- | --- |
| Upstream main base | `209abd403b7eaa968c6d4fa67be82e04b55706d6` |
| Evidence branch | `docs/post-hardening-release-evidence-20260513` |
| Evidence scope | Current `main` after PR #1850 and PR #1851 |
| Git remote | `https://github.com/affaan-m/everything-claude-code.git` |
| Local status caveat | Working tree had the unrelated untracked `docs/drafts/` directory |
The actual release operator should repeat these checks from the final release
commit with a clean checkout before publishing.
## Queue And Release State
| Surface | Command | Result |
| --- | --- | --- |
| GitHub PRs and issues | `gh pr list` / `gh issue list` across trunk, AgentShield, and JARVIS | 0 open PRs and 0 open issues on accessible `affaan-m` repos |
| Trunk discussions | GraphQL discussion count for `affaan-m/everything-claude-code` | 0 open discussions |
| Dependabot alerts | Dependabot alert API for trunk, AgentShield, and JARVIS | 0 open alerts |
| Release state | `gh release view v2.0.0-rc.1` | Still not created; release remains approval-gated |
ECC-Tools organization repo counts were not rechecked through the current
GraphQL token in this pass because the token cannot resolve those org repos.
The prior post-#42 local checkout handoff recorded both ECC-Tools repos at
0 open PRs and 0 open issues.
## Hardening Landed Since Previous Evidence
| PR | Merge commit | Evidence |
| --- | --- | --- |
| #1850 | `248673271455e9dc85b8add2a6ab76107b718639` | Removed `Bash` tool access from read-only analyzer agents and zh-CN copies; AgentShield high findings on that surface dropped 21 -> 18 with no new high findings |
| #1851 | `209abd403b7eaa968c6d4fa67be82e04b55706d6` | Disabled `actions/checkout` credential persistence in write-permission workflows and added a workflow-security validator rule to keep that guard in place |
## Required Command Evidence
| Evidence | Command | Result |
| --- | --- | --- |
| Harness audit | `npm run harness:audit -- --format json` | `overall_score: 70`, `max_score: 70`, no top actions |
| Adapter scorecard | `npm run harness:adapters -- --check` | `Harness Adapter Compliance: PASS`; 11 adapters |
| Observability readiness | `npm run observability:ready -- --format json` | `overall_score: 21`, `max_score: 21`, `ready: true`, no top actions; includes Release Safety 3/3 |
| Workflow security validator | `node scripts/ci/validate-workflow-security.js` | Validated 7 workflow files |
| Workflow validator tests | `node tests/ci/validate-workflow-security.test.js` | Passed 14/14 |
| Release surface | `node tests/docs/ecc2-release-surface.test.js` | Passed 18/18 |
| Package surface | `node tests/scripts/npm-publish-surface.test.js` | Passed 2/2 |
| Root suite | `node tests/run-all.js` | Passed 2381/2381, 0 failed |
| Markdown lint | `npx markdownlint-cli '**/*.md' --ignore node_modules --ignore docs/drafts` | Passed |
| Rust surface | `cd ecc2 && cargo test` | Passed 462/462; warnings only for unused functions/fields |
| GitGuardian Security Checks | GitHub check on post-hardening security PRs | Passed before merge |
## Supply-Chain Evidence
| Surface | Command or check | Result |
| --- | --- | --- |
| Local npm vulnerability audit | `npm audit --json` | 0 vulnerabilities |
| Local npm signature audit | `npm audit signatures` | 241 verified registry signatures and 30 verified attestations |
| Rust advisory audit | `cd ecc2 && cargo audit -q` | Passed silently |
| TanStack / Mini Shai-Hulud IOC check | Grep for affected package namespaces, payload filenames, and known commit marker | No runtime or lockfile dependency on affected packages; no worm IOC matches |
| GitGuardian Security Checks | GitHub check on post-hardening security PRs | Passed before merge |
## External Advisory Mapping
The May 2026 TanStack incident maps to ECC release risk through three workflow
classes:
- `pull_request_target` workflows that execute or checkout untrusted PR code;
- shared dependency caches crossing fork, base, and release workflow trust
boundaries;
- release jobs with writable tokens or OIDC tokens exposed to subsequent
process execution.
ECC's current guardrails cover those classes through:
- rejection of untrusted checkout refs in `workflow_run` and
`pull_request_target` workflows;
- rejection of shared caches in `pull_request_target` and `id-token: write`
workflows;
- mandatory `npm audit signatures` when workflows run `npm audit`;
- mandatory `npm ci --ignore-scripts` in workflows with write permissions;
- mandatory `persist-credentials: false` on `actions/checkout` in workflows
with write permissions.
## Blockers Still Requiring Approval Or External Action
- Create or verify GitHub prerelease `v2.0.0-rc.1`.
- Publish `ecc-universal@2.0.0-rc.1` with npm dist-tag `next`.
- Create and push the Claude plugin tag only after explicit approval.
- Confirm the live Claude/Codex/OpenCode marketplace submission path or record
the manual submission owner and status.
- Verify ECC Tools billing/App/Marketplace claims before using them in launch
copy.
- Refresh announcement copy with live URLs after release and package/plugin
URLs exist.

View File

@@ -10,6 +10,8 @@ For the May 12 dry-run evidence pass, see
[`publication-evidence-2026-05-12.md`](publication-evidence-2026-05-12.md).
For the May 13 release-readiness evidence refresh, see
[`publication-evidence-2026-05-13.md`](publication-evidence-2026-05-13.md).
For the May 13 post-hardening evidence refresh after PR #1850 and PR #1851, see
[`publication-evidence-2026-05-13-post-hardening.md`](publication-evidence-2026-05-13-post-hardening.md).
## Release Identity Matrix
@@ -39,6 +41,7 @@ For the May 13 release-readiness evidence refresh, see
| OpenCode package | Build output is regenerated from source and package metadata is current | `npm run build:opencode` | `Blocker: none for local build; public distribution still follows npm/plugin release` | Package owner | Evidence recorded |
| ECC Tools billing reference | Any billing claim links to verified Marketplace/App state | `gh api repos/ECC-Tools/ECC-Tools` plus app/marketplace URL check | `Blocker:` | ECC Tools owner | Pending |
| Announcement copy | X, LinkedIn, GitHub release, and longform copy point to live URLs | `rg -n "TODO" docs/releases/2.0.0-rc.1` and repeat for `TBD` | `Blocker:` | Release owner | Pending |
| Privileged workflow hardening | Release and maintenance workflows avoid persisted checkout tokens | `node scripts/ci/validate-workflow-security.js` | `Blocker:` | Release owner | Evidence recorded in post-hardening refresh |
## Required Command Evidence
@@ -49,8 +52,10 @@ Record the exact commit SHA and command output before any publication action:
| Clean release branch | `git status --short --branch` | On intended release commit; no unrelated files | Pending final clean-checkout release pass; May 13 evidence branch still had unrelated untracked `docs/drafts/` |
| Harness audit | `npm run harness:audit -- --format json` | 70/70 passing | `publication-evidence-2026-05-13.md`: 70/70 |
| Adapter scorecard | `npm run harness:adapters -- --check` | PASS | `publication-evidence-2026-05-13.md`: PASS, 11 adapters |
| Observability readiness | `npm run observability:ready` | 16/16 passing | `publication-evidence-2026-05-13.md`: 16/16, ready true |
| Root suite | `node tests/run-all.js` | 0 failures | `publication-evidence-2026-05-13.md`: 2376 passed, 0 failed |
| Observability readiness | `npm run observability:ready` | 21/21 passing | `publication-evidence-2026-05-13-post-hardening.md`: 21/21, ready true after release-safety gate refresh |
| Release safety gate | `npm run observability:ready -- --format json` | Release Safety category passing with publication readiness, supply-chain, workflow security, package surface, and release-surface evidence | `publication-evidence-2026-05-13-post-hardening.md`: Release Safety 3/3 |
| Supply-chain verification | `npm audit --json`; `npm audit signatures`; `cd ecc2 && cargo audit -q`; Dependabot alerts; GitGuardian Security Checks | 0 vulnerabilities/alerts, registry signatures verified, GitGuardian clean | `publication-evidence-2026-05-13-post-hardening.md`: npm, cargo, Dependabot, TanStack/Mini Shai-Hulud, and GitGuardian evidence |
| Root suite | `node tests/run-all.js` | 0 failures | `publication-evidence-2026-05-13-post-hardening.md`: 2381 passed, 0 failed |
| Markdown lint | `npx markdownlint-cli '**/*.md' --ignore node_modules` | 0 failures | `publication-evidence-2026-05-13.md`: passed after zh-CN CLAUDE list-marker normalization |
| Package surface | `node tests/scripts/npm-publish-surface.test.js` | 0 failures; no Python bytecode in npm tarball | `2/2` passed in May 12 evidence pass |
| Release surface | `node tests/docs/ecc2-release-surface.test.js` | 0 failures | `publication-evidence-2026-05-13.md`: 18/18 passed |

View File

@@ -8,7 +8,9 @@ they do not prove that the workflow executed the intended code path.
## Current External Trigger
As of 2026-05-13, the active incident class is the May 2026 TanStack npm
supply-chain compromise:
supply-chain compromise. ECC also keeps Mini Shai-Hulud-style npm worm IOCs in
the same release-safety sweep because both incident classes target package
install/publish paths and developer credentials:
- TanStack reported 84 malicious versions across 42 `@tanstack/*` packages,
published on 2026-05-11 between 19:20 and 19:26 UTC.

View File

@@ -243,6 +243,24 @@
"security"
]
},
{
"id": "lang:ruby",
"family": "language",
"description": "Ruby and Rails coding, testing, and security guidance. Resolves through framework-language and security modules.",
"modules": [
"framework-language",
"security"
]
},
{
"id": "framework:rails",
"family": "framework",
"description": "Rails 8 application guidance for MVC, Hotwire, Solid Queue/Cache/Cable, authentication, testing, and security.",
"modules": [
"framework-language",
"security"
]
},
{
"id": "lang:rust",
"family": "language",

View File

@@ -21,6 +21,7 @@ rules/
├── web/ # Web and frontend specific
├── swift/ # Swift specific
├── php/ # PHP specific
├── ruby/ # Ruby / Rails specific
└── arkts/ # HarmonyOS / ArkTS specific
```
@@ -40,6 +41,7 @@ rules/
./install.sh web
./install.sh swift
./install.sh php
./install.sh ruby
./install.sh arkts
# Install multiple languages at once
@@ -66,6 +68,7 @@ cp -r rules/golang ~/.claude/rules/golang
cp -r rules/web ~/.claude/rules/web
cp -r rules/swift ~/.claude/rules/swift
cp -r rules/php ~/.claude/rules/php
cp -r rules/ruby ~/.claude/rules/ruby
cp -r rules/arkts ~/.claude/rules/arkts
# Attention ! ! ! Configure according to your actual project requirements; the configuration here is for reference only.

View File

@@ -0,0 +1,46 @@
---
paths:
- "**/*.rb"
- "**/*.rake"
- "**/Gemfile"
- "**/*.gemspec"
- "**/config.ru"
---
# Ruby Coding Style
> This file extends [common/coding-style.md](../common/coding-style.md) with Ruby and Rails specific content.
## Standards
- Target **Ruby 3.3+** for new Rails work unless the project already pins an older supported runtime.
- Enable **YJIT** in production only after measuring boot time, memory, and request/job throughput.
- Add `# frozen_string_literal: true` to new Ruby files when the project uses that convention.
- Prefer clear Ruby over clever metaprogramming; isolate DSL-heavy code behind narrow, tested boundaries.
## Formatting And Linting
- Use the project's checked-in RuboCop config. For Rails 8+ apps, start from `rubocop-rails-omakase` and customize only where the codebase has a real convention.
- Keep formatter/linter commands behind binstubs or scripts so CI and local runs match:
```bash
bundle exec rubocop
bundle exec rubocop -A
```
- Do not silence cops inline unless the exception is narrow, documented, and harder to express cleanly in code.
## Rails Style
- Follow Rails naming and directory conventions before adding custom structure.
- Keep controllers transport-focused: authentication, authorization, parameter handling, response shape.
- Put reusable domain behavior in models, concerns, service objects, query objects, or form objects based on actual complexity, not as default ceremony.
- Prefer `bin/rails`, `bin/rake`, and checked-in binstubs over globally installed commands.
## Error Handling
- Rescue specific exceptions. Avoid broad `rescue StandardError` blocks unless they re-raise or preserve enough context for operators.
- Use `ActiveSupport::Notifications` or the app's logger for operational events; do not leave `puts`, `pp`, or `debugger` in committed application code.
## Reference
See skill: `backend-patterns` for broader service/repository layering guidance.

37
rules/ruby/hooks.md Normal file
View File

@@ -0,0 +1,37 @@
---
paths:
- "**/*.rb"
- "**/*.rake"
- "**/Gemfile"
- "**/Gemfile.lock"
- "**/config/routes.rb"
---
# Ruby Hooks
> This file extends [common/hooks.md](../common/hooks.md) with Ruby and Rails specific content.
## PostToolUse Hooks
Configure project-local hooks to prefer binstubs and checked-in tooling:
- **RuboCop**: run `bundle exec rubocop -A <file>` or the project's safer formatter command after Ruby edits.
- **Brakeman**: run `bundle exec brakeman --no-pager` after security-sensitive Rails changes.
- **Tests**: run the narrowest matching `bin/rails test ...` or `bundle exec rspec ...` command for touched files.
- **Bundler audit**: run `bundle exec bundle-audit check --update` when `Gemfile` or `Gemfile.lock` changes and the project has bundler-audit installed.
## Warnings
- Warn on committed `debugger`, `binding.irb`, `binding.pry`, `puts`, `pp`, or `p` calls in application code.
- Warn when an edit disables CSRF protection, expands mass-assignment, or adds raw SQL without parameterization.
- Warn when a migration changes data destructively without a reversible path or documented rollout plan.
## CI Gate Suggestions
```bash
bundle exec rubocop
bundle exec brakeman --no-pager
bin/rails test
bundle exec rspec
```
Use only the commands that are present in the project; do not install new hook dependencies without maintainer approval.

44
rules/ruby/patterns.md Normal file
View File

@@ -0,0 +1,44 @@
---
paths:
- "**/*.rb"
- "**/*.rake"
- "**/Gemfile"
- "**/app/**/*.erb"
- "**/config/routes.rb"
---
# Ruby Patterns
> This file extends [common/patterns.md](../common/patterns.md) with Ruby and Rails specific content.
## Rails Way First
- Start with plain Rails MVC and Active Record conventions for small and medium features.
- Introduce service objects, query objects, form objects, decorators, or presenters when the model/controller boundary is carrying multiple responsibilities.
- Name extracted objects after the business operation they perform, not after generic layers like `Manager` or `Processor`.
## Persistence
- Prefer PostgreSQL for multi-host production Rails apps unless the existing platform has a clear reason for MySQL or SQLite.
- Treat Rails 8 SQLite-backed defaults as viable for single-host or modest deployments, not as an automatic fit for shared multi-service systems.
- Keep raw SQL behind query objects or model scopes and parameterize every dynamic value.
## Background Jobs And Runtime Services
- Use **Solid Queue** for greenfield Rails 8 apps with modest throughput and simple deployment needs.
- Use **Sidekiq** when the app needs mature observability, high throughput, existing Redis infrastructure, or Pro/Enterprise features.
- Use **Solid Cache** and **Solid Cable** when their deployment model matches the app; use Redis when shared cross-service behavior, high fanout, or advanced data structures matter.
## Frontend
- Prefer **Hotwire** with Turbo, Stimulus, Importmap, and Propshaft for server-rendered Rails apps.
- Use React, Vue, Inertia.js, or a separate SPA when interaction complexity, existing product architecture, or team ownership justifies the extra client surface.
- Keep view components, partials, and presenters focused on rendering decisions; keep persistence and authorization out of templates.
## Authentication
- Use the Rails 8 authentication generator for straightforward session auth and password reset needs.
- Use Devise or another established auth system when requirements include OAuth, MFA, confirmable/lockable flows, multi-model auth, or a large existing Devise footprint.
## Reference
See skill: `backend-patterns` for service boundaries and adapter patterns.

51
rules/ruby/security.md Normal file
View File

@@ -0,0 +1,51 @@
---
paths:
- "**/*.rb"
- "**/*.rake"
- "**/Gemfile"
- "**/Gemfile.lock"
- "**/config/routes.rb"
- "**/config/credentials*.yml.enc"
---
# Ruby Security
> This file extends [common/security.md](../common/security.md) with Ruby and Rails specific content.
## Rails Defaults
- Keep CSRF protection enabled for state-changing browser requests.
- Use strong parameters or typed boundary objects before mass assignment.
- Store secrets in Rails credentials, environment variables, or a secret manager. Never commit plaintext keys, tokens, private credentials, or copied `.env` values.
## SQL And Active Record
- Prefer Active Record query APIs and parameterized SQL.
- Never interpolate request, cookie, header, job, or webhook values into SQL strings.
- Scope model callbacks carefully; security-sensitive side effects should be explicit and covered by tests.
## Authentication And Sessions
- Use the Rails 8 authentication generator for simple session auth, or Devise when OAuth, MFA, confirmable, lockable, multi-model auth, or existing Devise conventions are required.
- Rotate sessions after sign-in and privilege changes.
- Protect account recovery flows with expiry, single-use tokens, rate limiting, and audit logging.
## Dependencies
- Run dependency checks when the lockfile changes:
```bash
bundle audit check --update
bundle exec brakeman --no-pager
```
- Review new gems for maintainer activity, native extension risk, transitive dependencies, and whether the same behavior can be implemented with Rails core.
## Web Safety
- Escape template output by default. Treat `html_safe`, `raw`, and custom sanitizers as security-sensitive code.
- Validate file uploads by content type, extension, size, and storage destination.
- Treat background jobs, webhooks, Action Cable messages, and Turbo Stream inputs as untrusted boundaries.
## Reference
See skill: `security-review` for secure-by-default review patterns.

51
rules/ruby/testing.md Normal file
View File

@@ -0,0 +1,51 @@
---
paths:
- "**/*.rb"
- "**/*.rake"
- "**/Gemfile"
- "**/test/**/*.rb"
- "**/spec/**/*.rb"
- "**/config/routes.rb"
---
# Ruby Testing
> This file extends [common/testing.md](../common/testing.md) with Ruby and Rails specific content.
## Framework
- Use **Minitest** when the Rails app follows the default Rails test stack.
- Use **RSpec** when it is already established in the project or the team has explicit production conventions around it.
- Do not mix Minitest and RSpec inside the same feature area without a migration reason.
## Test Pyramid
- Put fast domain behavior in model, service, query, policy, and job tests.
- Use request/controller tests for HTTP contracts, auth behavior, redirects, status codes, and response shapes.
- Use system tests with Capybara for browser-critical flows only; keep them focused and stable.
- Cover background jobs with unit tests for behavior and integration tests for queue/enqueue contracts.
## Fixtures And Factories
- Use Rails fixtures when they are the project default and the data graph is small.
- Use `factory_bot` when scenarios need explicit object construction or complex traits.
- Keep test data close to the behavior being asserted; avoid global fixtures that hide setup cost.
## Commands
Prefer project-local commands:
```bash
bin/rails test
bin/rails test test/models/user_test.rb
bundle exec rspec
bundle exec rspec spec/models/user_spec.rb
```
## Coverage
- Use SimpleCov when coverage is enforced; keep thresholds in CI and avoid gaming branch coverage with low-value tests.
- Add regression tests for bug fixes before changing production code.
## Reference
See skill: `tdd-workflow` for the repo-wide RED -> GREEN -> REFACTOR loop.

View File

@@ -7,12 +7,13 @@
* the actual code. This hook steers the agent back to fixing the source.
*
* Exit codes:
* 0 = allow (not a config file)
* 2 = block (config file modification attempted)
* 0 = allow (not a config file, or first-time creation of one)
* 2 = block (existing config file modification attempted)
*/
'use strict';
const fs = require('fs');
const path = require('path');
const MAX_STDIN = 1024 * 1024;
@@ -58,7 +59,7 @@ const PROTECTED_FILES = new Set([
'.stylelintrc.yml',
'.markdownlint.json',
'.markdownlint.yaml',
'.markdownlintrc',
'.markdownlintrc'
]);
function parseInput(inputOrRaw) {
@@ -94,13 +95,41 @@ function run(inputOrRaw, options = {}) {
const basename = path.basename(filePath);
if (PROTECTED_FILES.has(basename)) {
// Allow first-time creation — there's no existing config to weaken.
// The hook's purpose is blocking modifications; writing a brand-new
// config file in a project that has none is a legitimate bootstrap
// path (e.g. scaffolding ESLint into a fresh repo).
//
// Fail closed on any stat error other than ENOENT. Use lstatSync so a
// symlink at the protected path is treated as present even if its target
// is missing — a dangling symlink at e.g. .eslintrc.js still represents
// an existing config entry that an agent should not silently replace.
// fs.existsSync would swallow EACCES/EPERM as false; lstatSync exposes
// the error code so we can treat only genuine "path not found" (ENOENT)
// as absent.
let exists = true;
try {
fs.lstatSync(filePath);
// lstat succeeded — something (file, dir, or symlink) exists here.
} catch (err) {
if (err && err.code === 'ENOENT') {
exists = false;
}
// Any other error (EACCES, EPERM, ELOOP, etc.) leaves exists=true
// so the guard is never silently weakened.
}
if (!exists) {
return { exitCode: 0 };
}
return {
exitCode: 2,
stderr:
`BLOCKED: Modifying ${basename} is not allowed. ` +
'Fix the source code to satisfy linter/formatter rules instead of ' +
'weakening the config. If this is a legitimate config change, ' +
'disable the config-protection hook temporarily.',
'disable the config-protection hook temporarily.'
};
}
@@ -125,7 +154,7 @@ process.stdin.on('data', chunk => {
process.stdin.on('end', () => {
const result = run(raw, {
truncated,
maxStdin: Number(process.env.ECC_HOOK_INPUT_MAX_BYTES) || MAX_STDIN,
maxStdin: Number(process.env.ECC_HOOK_INPUT_MAX_BYTES) || MAX_STDIN
});
if (result.stderr) {

View File

@@ -51,6 +51,8 @@ const LEGACY_LANGUAGE_ALIAS_TO_CANONICAL = Object.freeze({
perl: 'perl',
php: 'php',
python: 'python',
rails: 'ruby',
ruby: 'ruby',
rust: 'rust',
swift: 'swift',
typescript: 'typescript',
@@ -66,6 +68,7 @@ const LEGACY_LANGUAGE_EXTRA_MODULE_IDS = Object.freeze({
perl: [],
php: [],
python: ['framework-language'],
ruby: ['framework-language', 'security'],
rust: ['framework-language'],
swift: [],
typescript: ['framework-language'],

View File

@@ -127,6 +127,13 @@ function buildChecks(rootDir) {
const progressSyncContract = readText(rootDir, 'docs/architecture/progress-sync-contract.md');
const gaRoadmap = readText(rootDir, 'docs/ECC-2.0-GA-ROADMAP.md');
const workItems = readText(rootDir, 'scripts/work-items.js');
const publicationReadiness = readText(rootDir, 'docs/releases/2.0.0-rc.1/publication-readiness.md');
const postHardeningEvidence = readText(rootDir, 'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-13-post-hardening.md');
const supplyChainIncidentResponse = readText(rootDir, 'docs/security/supply-chain-incident-response.md');
const workflowSecurityValidator = readText(rootDir, 'scripts/ci/validate-workflow-security.js');
const workflowSecurityValidatorTests = readText(rootDir, 'tests/ci/validate-workflow-security.test.js');
const publishSurfaceTest = readText(rootDir, 'tests/scripts/npm-publish-surface.test.js');
const releaseSurfaceTest = readText(rootDir, 'tests/docs/ecc2-release-surface.test.js');
const hudStatusFixture = safeParseJson(readText(rootDir, 'examples/hud-status-contract.json')) || {};
const quickstart = readText(rootDir, 'docs/releases/2.0.0-rc.1/quickstart.md');
const releaseNotes = readText(rootDir, 'docs/releases/2.0.0-rc.1/release-notes.md');
@@ -275,6 +282,56 @@ function buildChecks(rootDir) {
]),
fix: 'Add the progress sync contract, link it from the GA roadmap, and preserve work-items GitHub sync.'
},
{
id: 'release-safety-evidence',
category: 'Release Safety',
points: 3,
path: 'docs/releases/2.0.0-rc.1/publication-readiness.md',
description: 'Release readiness includes package, workflow, and supply-chain evidence before publication',
pass: fileExists(rootDir, 'docs/releases/2.0.0-rc.1/publication-readiness.md')
&& fileExists(rootDir, 'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-13-post-hardening.md')
&& fileExists(rootDir, 'docs/security/supply-chain-incident-response.md')
&& fileExists(rootDir, 'scripts/ci/validate-workflow-security.js')
&& fileExists(rootDir, 'tests/ci/validate-workflow-security.test.js')
&& fileExists(rootDir, 'tests/scripts/npm-publish-surface.test.js')
&& fileExists(rootDir, 'tests/docs/ecc2-release-surface.test.js')
&& includesAll(publicationReadiness, [
'Publication Gates',
'Required Command Evidence',
'Do Not Publish If',
'npm dist-tag',
'GitGuardian',
'Dependabot alerts',
'npm audit signatures'
])
&& includesAll(postHardeningEvidence, [
'npm audit --json',
'npm audit signatures',
'cargo audit',
'Dependabot alert API',
'TanStack',
'Mini Shai-Hulud',
'GitGuardian Security Checks'
])
&& includesAll(supplyChainIncidentResponse, [
'TanStack',
'Mini Shai-Hulud',
'npm audit signatures',
'trusted publishing',
'pull_request_target',
'id-token: write'
])
&& includesAll(workflowSecurityValidator, [
'persist-credentials: false',
'npm audit signatures',
'pull_request_target',
'id-token: write'
])
&& includesAll(workflowSecurityValidatorTests, ['npm audit signatures', 'persist-credentials: false'])
&& includesAll(publishSurfaceTest, ['npm pack', 'Python bytecode'])
&& includesAll(releaseSurfaceTest, ['publication-readiness.md']),
fix: 'Refresh publication readiness, post-hardening evidence, supply-chain response docs, workflow-security validator coverage, and package/release surface tests.'
},
{
id: 'package-exposes-readiness-gate',
category: 'Packaging',

View File

@@ -82,6 +82,27 @@ def _normalize_remote_url(remote_url: str) -> str:
return normalized.lower() if is_network else normalized
def _stream_can_encode(text: str, stream=None) -> bool:
stream = stream or sys.stdout
encoding = getattr(stream, "encoding", None) or sys.getdefaultencoding()
try:
text.encode(encoding)
except (LookupError, UnicodeEncodeError):
return False
return True
def _confidence_bar(confidence, stream=None) -> str:
try:
filled = int(float(confidence) * 10)
except (TypeError, ValueError):
filled = 5
filled = max(0, min(10, filled))
full, empty = ("\u2588", "\u2591") if _stream_can_encode("\u2588\u2591", stream) else ("#", ".")
return full * filled + empty * (10 - filled)
def _project_hash(value: str) -> str:
return hashlib.sha256(value.encode("utf-8")).hexdigest()[:12]
@@ -550,7 +571,7 @@ def _print_instincts_by_domain(instincts: list[dict]) -> None:
for inst in sorted(domain_instincts, key=lambda x: -x.get('confidence', 0.5)):
conf = inst.get('confidence', 0.5)
conf_bar = '\u2588' * int(conf * 10) + '\u2591' * (10 - int(conf * 10))
conf_bar = _confidence_bar(conf)
trigger = inst.get('trigger', 'unknown trigger')
scope_tag = f"[{inst.get('scope', '?')}]"

View File

@@ -45,6 +45,7 @@ _find_cross_project_instincts = _mod._find_cross_project_instincts
load_registry = _mod.load_registry
_validate_instinct_id = _mod._validate_instinct_id
_update_registry = _mod._update_registry
_confidence_bar = _mod._confidence_bar
# ─────────────────────────────────────────────
@@ -642,6 +643,39 @@ def test_cmd_status_with_instincts(patch_globals, monkeypatch, capsys):
assert "GLOBAL" in out
def test_confidence_bar_uses_unicode_when_supported():
"""Confidence bars should retain block glyphs on UTF-8 streams."""
stream = SimpleNamespace(encoding="utf-8")
assert _confidence_bar(0.8, stream=stream) == "\u2588" * 8 + "\u2591" * 2
def test_confidence_bar_uses_ascii_when_stream_rejects_block_glyphs():
"""Windows cp1252 streams cannot encode block glyphs."""
stream = SimpleNamespace(encoding="cp1252")
assert _confidence_bar(0.8, stream=stream) == "########.."
def test_print_instincts_by_domain_is_cp1252_safe(monkeypatch):
"""Status rendering should not crash on Windows cp1252 stdout."""
raw = io.BytesIO()
stream = io.TextIOWrapper(raw, encoding="cp1252")
monkeypatch.setattr(_mod.sys, "stdout", stream)
_mod._print_instincts_by_domain([{
"id": "windows-safe",
"trigger": "when stdout uses cp1252",
"confidence": 0.8,
"domain": "platform",
"scope": "project",
}])
stream.flush()
out = raw.getvalue().decode("cp1252")
assert "########.." in out
assert "\u2588" not in out
assert "\u2591" not in out
def test_cmd_status_returns_int(patch_globals, monkeypatch):
"""cmd_status should always return an int."""
tree = patch_globals

View File

@@ -130,12 +130,12 @@ test('candidate playbook preserves stale-salvage operating rules', () => {
}
});
test('roadmap points to the evaluator RAG prototype and keeps hosted integration open', () => {
test('roadmap points to the evaluator RAG prototype and hosted PR check', () => {
const roadmap = read('docs/ECC-2.0-GA-ROADMAP.md');
assert.ok(roadmap.includes('docs/architecture/evaluator-rag-prototype.md'));
assert.ok(roadmap.includes('examples/evaluator-rag-prototype/'));
assert.ok(roadmap.includes('Local corpus complete; hosted integration remains future'));
assert.ok(roadmap.includes('Deterministic hosted PR check and cached output scoring integrated; hosted retrieval remains future'));
});
test('billing readiness scenario rejects launch copy overclaims', () => {

View File

@@ -4,6 +4,7 @@
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawnSync } = require('child_process');
@@ -70,85 +71,249 @@ function runTests() {
let passed = 0;
let failed = 0;
if (test('blocks protected config file edits through run-with-flags', () => {
const input = {
tool_name: 'Write',
tool_input: {
file_path: '.eslintrc.js',
content: 'module.exports = {};'
if (
test('blocks protected config file edits through run-with-flags', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
try {
const absPath = path.join(tmpDir, '.eslintrc.js');
fs.writeFileSync(absPath, 'module.exports = {};');
const input = {
tool_name: 'Write',
tool_input: {
file_path: absPath,
content: 'module.exports = {};'
}
};
const result = runHook(input);
assert.strictEqual(result.code, 2, 'Expected protected config edit to be blocked');
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
};
})
)
passed++;
else failed++;
const result = runHook(input);
assert.strictEqual(result.code, 2, 'Expected protected config edit to be blocked');
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
})) passed++; else failed++;
if (
test('passes through safe file edits unchanged', () => {
const input = {
tool_name: 'Write',
tool_input: {
file_path: 'src/index.js',
content: 'console.log("ok");'
}
};
if (test('passes through safe file edits unchanged', () => {
const input = {
tool_name: 'Write',
tool_input: {
file_path: 'src/index.js',
content: 'console.log("ok");'
}
};
const rawInput = JSON.stringify(input);
const result = runHook(input);
assert.strictEqual(result.code, 0, 'Expected safe file edit to pass');
assert.strictEqual(result.stdout, rawInput, 'Expected exact raw JSON passthrough');
assert.strictEqual(result.stderr, '', 'Expected no stderr for safe edits');
})) passed++; else failed++;
if (test('blocks truncated protected config payloads instead of failing open', () => {
const rawInput = JSON.stringify({
tool_name: 'Write',
tool_input: {
file_path: '.eslintrc.js',
content: 'x'.repeat(1024 * 1024 + 2048)
}
});
const result = runHook(rawInput);
assert.strictEqual(result.code, 2, 'Expected truncated protected payload to be blocked');
assert.strictEqual(result.stdout, '', 'Blocked truncated payload should not echo raw input');
assert.ok(result.stderr.includes('Hook input exceeded 1048576 bytes'), `Expected size warning, got: ${result.stderr}`);
assert.ok(result.stderr.includes('truncated payload'), `Expected truncated payload warning, got: ${result.stderr}`);
})) passed++; else failed++;
if (test('legacy hooks do not echo raw input when they fail without stdout', () => {
const pluginRoot = path.join(__dirname, '..', `tmp-runner-plugin-${Date.now()}`);
const scriptDir = path.join(pluginRoot, 'scripts', 'hooks');
const scriptPath = path.join(scriptDir, 'legacy-block.js');
try {
fs.mkdirSync(scriptDir, { recursive: true });
fs.writeFileSync(
scriptPath,
'#!/usr/bin/env node\nprocess.stderr.write("blocked by legacy hook\\n");\nprocess.exit(2);\n'
);
const rawInput = JSON.stringify(input);
const result = runHook(input);
assert.strictEqual(result.code, 0, 'Expected safe file edit to pass');
assert.strictEqual(result.stdout, rawInput, 'Expected exact raw JSON passthrough');
assert.strictEqual(result.stderr, '', 'Expected no stderr for safe edits');
})
)
passed++;
else failed++;
if (
test('blocks truncated protected config payloads instead of failing open', () => {
const rawInput = JSON.stringify({
tool_name: 'Write',
tool_input: {
file_path: '.eslintrc.js',
content: 'module.exports = {};'
content: 'x'.repeat(1024 * 1024 + 2048)
}
});
const result = runCustomHook(pluginRoot, 'pre:legacy-block', 'scripts/hooks/legacy-block.js', rawInput);
assert.strictEqual(result.code, 2, 'Expected failing legacy hook exit code to propagate');
assert.strictEqual(result.stdout, '', 'Expected failing legacy hook to avoid raw passthrough');
assert.ok(result.stderr.includes('blocked by legacy hook'), `Expected legacy hook stderr, got: ${result.stderr}`);
} finally {
const result = runHook(rawInput);
assert.strictEqual(result.code, 2, 'Expected truncated protected payload to be blocked');
assert.strictEqual(result.stdout, '', 'Blocked truncated payload should not echo raw input');
assert.ok(result.stderr.includes('Hook input exceeded 1048576 bytes'), `Expected size warning, got: ${result.stderr}`);
assert.ok(result.stderr.includes('truncated payload'), `Expected truncated payload warning, got: ${result.stderr}`);
})
)
passed++;
else failed++;
if (
test('allows first-time creation of a protected config file', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
try {
fs.rmSync(pluginRoot, { recursive: true, force: true });
} catch {
// best-effort cleanup
const absPath = path.join(tmpDir, 'eslint.config.mjs');
const input = {
tool_name: 'Write',
tool_input: {
file_path: absPath,
content: 'export default [];'
}
};
const rawInput = JSON.stringify(input);
const result = runHook(input);
assert.strictEqual(result.code, 0, `Expected exit 0 for first-time creation, got ${result.code}; stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, rawInput, 'Expected raw passthrough when creation is allowed');
assert.strictEqual(result.stderr, '', `Expected no stderr for first-time creation, got: ${result.stderr}`);
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
}
})) passed++; else failed++;
})
)
passed++;
else failed++;
if (
test('allows first-time creation when the parent directory does not exist yet', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
try {
// Path under a non-existent subdirectory — statSync returns ENOENT
// on the final segment, which should be treated as "does not exist"
// and allow the write. (Agent or CLI is expected to create parents
// during the Write itself; this hook does not need to.)
const absPath = path.join(tmpDir, 'no-such-parent', '.prettierrc');
const input = {
tool_name: 'Write',
tool_input: {
file_path: absPath,
content: '{}'
}
};
const rawInput = JSON.stringify(input);
const result = runHook(input);
assert.strictEqual(result.code, 0, `Expected exit 0 for ENOENT path, got ${result.code}; stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, rawInput, 'Expected raw passthrough when path does not exist');
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
})
)
passed++;
else failed++;
if (
test('blocks protected paths that exist as a dangling symlink', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
try {
const missingTarget = path.join(tmpDir, 'nowhere.js');
const linkPath = path.join(tmpDir, '.eslintrc.js');
try {
fs.symlinkSync(missingTarget, linkPath);
} catch (err) {
// Windows without Developer Mode or certain sandboxes disallow
// symlinks. Skip cleanly rather than fail the suite.
if (err.code === 'EPERM' || err.code === 'EACCES') {
console.log(' (skipped: symlink creation not permitted here)');
return;
}
throw err;
}
const input = {
tool_name: 'Write',
tool_input: {
file_path: linkPath,
content: 'module.exports = {};'
}
};
const result = runHook(input);
assert.strictEqual(result.code, 2, `Expected exit 2 for dangling symlink, got ${result.code}; stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
assert.ok(
result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'),
`Expected block message, got: ${result.stderr}`
);
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
})
)
passed++;
else failed++;
if (
test('still blocks writes to an existing protected config file', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
try {
const absPath = path.join(tmpDir, '.eslintrc.js');
fs.writeFileSync(absPath, 'module.exports = { rules: {} };');
const input = {
tool_name: 'Edit',
tool_input: {
file_path: absPath,
content: 'module.exports = { rules: { "no-console": "off" } };'
}
};
const result = runHook(input);
assert.strictEqual(result.code, 2, 'Expected exit 2 when modifying an existing protected config');
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
})
)
passed++;
else failed++;
if (
test('legacy hooks do not echo raw input when they fail without stdout', () => {
const pluginRoot = path.join(__dirname, '..', `tmp-runner-plugin-${Date.now()}`);
const scriptDir = path.join(pluginRoot, 'scripts', 'hooks');
const scriptPath = path.join(scriptDir, 'legacy-block.js');
try {
fs.mkdirSync(scriptDir, { recursive: true });
fs.writeFileSync(scriptPath, '#!/usr/bin/env node\nprocess.stderr.write("blocked by legacy hook\\n");\nprocess.exit(2);\n');
const rawInput = JSON.stringify({
tool_name: 'Write',
tool_input: {
file_path: '.eslintrc.js',
content: 'module.exports = {};'
}
});
const result = runCustomHook(pluginRoot, 'pre:legacy-block', 'scripts/hooks/legacy-block.js', rawInput);
assert.strictEqual(result.code, 2, 'Expected failing legacy hook exit code to propagate');
assert.strictEqual(result.stdout, '', 'Expected failing legacy hook to avoid raw passthrough');
assert.ok(result.stderr.includes('blocked by legacy hook'), `Expected legacy hook stderr, got: ${result.stderr}`);
} finally {
try {
fs.rmSync(pluginRoot, { recursive: true, force: true });
} catch {
// best-effort cleanup
}
}
})
)
passed++;
else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);

View File

@@ -143,6 +143,8 @@ function runTests() {
const languages = listAvailableLanguages(sourceRoot);
assert.ok(languages.includes('typescript'));
assert.ok(languages.includes('ruby'));
assert.ok(languages.includes('rails'));
assert.ok(languages.includes('zig'));
assert.ok(!languages.includes('common'));
assert.deepStrictEqual([...languages].sort(), languages);

View File

@@ -176,6 +176,8 @@ function runTests() {
assert.ok(languages.includes('golang'));
assert.ok(languages.includes('kotlin'));
assert.ok(languages.includes('rust'));
assert.ok(languages.includes('ruby'));
assert.ok(languages.includes('rails'));
assert.ok(languages.includes('cpp'));
assert.ok(languages.includes('c'));
assert.ok(languages.includes('csharp'));
@@ -432,6 +434,22 @@ function runTests() {
'fsharp should resolve to framework-language module');
})) passed++; else failed++;
if (test('resolves ruby and rails legacy compatibility into framework-language and security modules', () => {
const selection = resolveLegacyCompatibilitySelection({
target: 'cursor',
legacyLanguages: ['ruby', 'rails'],
});
assert.deepStrictEqual(selection.canonicalLegacyLanguages, ['ruby', 'ruby']);
assert.ok(selection.moduleIds.includes('rules-core'));
assert.strictEqual(selection.moduleIds.filter(moduleId => moduleId === 'framework-language').length, 1);
assert.strictEqual(selection.moduleIds.filter(moduleId => moduleId === 'security').length, 1);
assert.ok(selection.moduleIds.includes('framework-language'),
'ruby should resolve to framework-language module');
assert.ok(selection.moduleIds.includes('security'),
'rails alias should add security guidance for Rails apps');
})) passed++; else failed++;
if (test('keeps antigravity legacy compatibility selections target-safe', () => {
const selection = resolveLegacyCompatibilitySelection({
target: 'antigravity',

View File

@@ -236,6 +236,7 @@ function runTests() {
assert.ok(components.some(c => c.id === 'lang:python'), 'Should have lang:python');
assert.ok(components.some(c => c.id === 'lang:go'), 'Should have lang:go');
assert.ok(components.some(c => c.id === 'lang:java'), 'Should have lang:java');
assert.ok(components.some(c => c.id === 'lang:ruby'), 'Should have lang:ruby');
})) passed++; else failed++;
if (test('component catalog includes framework: family entries', () => {
@@ -244,6 +245,7 @@ function runTests() {
assert.ok(components.some(c => c.id === 'framework:nextjs'), 'Should have framework:nextjs');
assert.ok(components.some(c => c.id === 'framework:django'), 'Should have framework:django');
assert.ok(components.some(c => c.id === 'framework:springboot'), 'Should have framework:springboot');
assert.ok(components.some(c => c.id === 'framework:rails'), 'Should have framework:rails');
})) passed++; else failed++;
if (test('component catalog includes capability: family entries', () => {

View File

@@ -92,7 +92,43 @@ function seedMinimalRepo(rootDir, overrides = {}) {
sync: {}
}, null, 2),
'docs/releases/2.0.0-rc.1/quickstart.md': 'observability-readiness.md',
'docs/releases/2.0.0-rc.1/release-notes.md': 'observability-readiness.md'
'docs/releases/2.0.0-rc.1/release-notes.md': 'observability-readiness.md',
'docs/releases/2.0.0-rc.1/publication-readiness.md': [
'Publication Gates',
'Required Command Evidence',
'Do Not Publish If',
'npm dist-tag',
'GitGuardian',
'Dependabot alerts',
'npm audit signatures'
].join('\n'),
'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-13-post-hardening.md': [
'npm audit --json',
'npm audit signatures',
'cargo audit',
'Dependabot alert API',
'TanStack',
'Mini Shai-Hulud',
'GitGuardian Security Checks'
].join('\n'),
'docs/security/supply-chain-incident-response.md': [
'TanStack',
'Mini Shai-Hulud',
'npm audit signatures',
'trusted publishing',
'pull_request_target',
'id-token: write'
].join('\n'),
'scripts/ci/validate-workflow-security.js': [
'persist-credentials: false',
'npm audit signatures',
'pull_request_target',
'id-token: write',
'shared cache'
].join('\n'),
'tests/ci/validate-workflow-security.test.js': 'npm audit signatures persist-credentials: false',
'tests/scripts/npm-publish-surface.test.js': 'npm pack --dry-run Python bytecode',
'tests/docs/ecc2-release-surface.test.js': 'publication-readiness.md',
};
for (const [relativePath, content] of Object.entries({ ...files, ...overrides })) {
@@ -258,6 +294,23 @@ function runTests() {
}
})) passed++; else failed++;
if (test('missing release safety evidence fails without disturbing live status checks', () => {
const projectRoot = createTempDir('observability-readiness-release-safety-fail-');
try {
seedMinimalRepo(projectRoot, {
'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-13-post-hardening.md': 'npm audit --json only'
});
const report = buildReport(projectRoot);
assert.strictEqual(report.ready, false);
assert.ok(report.checks.some(check => check.id === 'release-safety-evidence' && !check.pass));
assert.ok(report.checks.some(check => check.id === 'loop-status-live-signal' && check.pass));
} finally {
cleanup(projectRoot);
}
})) passed++; else failed++;
console.log('\nResults:');
console.log(` Passed: ${passed}`);
console.log(` Failed: ${failed}`);