Skip to content

docs: MRR-biased ECC Pro + AgentShield security roadmap - #2321

Merged
affaan-m merged 55 commits into
mainfrom
docs/ecc-pro-security-roadmap
Jul 4, 2026
Merged

affaan-m merged 55 commits into
mainfrom
docs/ecc-pro-security-roadmap

Conversation

@affaan-m

Copy link
Copy Markdown
Owner

What

Adds docs/ECC-PRO-SECURITY-ROADMAP.md — an MRR-biased product/security roadmap for ECC Pro and AgentShield, plus the reusable workflow script (.claude/workflows/ecc-pro-security-roadmap.js) that generated it.

It's the output of a multi-agent pass: a capability map of AgentShield and ECC Pro, triage of every open PR/issue on both repos, and web research on competitors, unbuilt ideas, and dev-tool demand. 17 items across 4 themes (now/next/later), each scored for effort × impact and linked to the real PRs/issues that implement it.

Headline

ecc-agentshield is doing ~30K downloads/month (903★) with almost no bridge to paid ECC Pro, and the most ownable paid surface — the agent-proximity "airspace" moat — is fully computed but never rendered. The roadmap is built around three moves:

  1. Now — remove conversion blockers: kill the false-positive cluster (the scanner penalizes its own recommended fix), render the 3D airspace dashboard (feat(control-pane): 3D agent-airspace viz + /api/proximity feed (Layer 4 observability) #2320), add a Pro CTA to the free funnel, ship verified correctness/Windows fixes, harden continuous-learning storage (bug: _remove_project_storage lacks path containment check #2297/fix: _write_registry missing file lock (race condition with _update_registry) #2294).
  2. Next — build recurring-revenue surfaces whose data models already exist locally: hosted continuous-scanning dashboard ("Sentry for agent security"), inline PR review + autofix-PR, rule-pack loader + intel feed (How does `/learn` work? #101), LLM-judge Deep Scan, compliance packs, central org policy/RBAC.
  3. Later — flagship bets: free runtime guard + Pro telemetry (agent EDR), cross-machine team airspace + A2A topology security, community MCP reputation registry.

Consistent strategy: keep the free, zero-account, local-first scanner as the moat; monetize everything that needs hosting, persisted fleet state, or a continuously-updated intel feed.

Notes

  • Research/triage only — no code changed beyond the doc + workflow script. The roadmap proposes the work; it doesn't do it.
  • One research thread (recent agentic/MCP CVEs) was blocked by an automated usage-policy classifier; the CVE-DB-refresh need is folded into the rule-pack/intel-feed item and will be handled as a scoped defensive OSV/GHSA/NVD sync.
  • markdownlint clean, ASCII-only (unicode-safety check passes).

Output of a multi-agent survey + research pass: capability map of AgentShield
and ECC Pro, triage of every open PR/issue on both repos, and web research on
competitors, unbuilt ideas, and dev-tool demand. 17 items across 4 themes
(now/next/later) scored for free-to-paid conversion, each linked to the real
PRs/issues that implement it. Includes the reusable workflow script that
generated it.

Headline: ecc-agentshield is ~30K downloads/month with near-zero monetization
bridge, and the agent-proximity moat is computed but never rendered. Roadmap
removes trust blockers (FP cluster), makes the moat visible (PR #2320), then
productizes local CLI primitives into hosted Pro surfaces.
@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b91bf73e-e30a-465b-aea0-0f8c97a50269

📥 Commits

Reviewing files that changed from the base of the PR and between a26a0d5 and b8df3e0.

⛔ Files ignored due to path filters (3)
  • ecc2/Cargo.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (121)
  • .agents/skills/tdd-workflow/SKILL.md
  • .claude-plugin/marketplace.json
  • .claude-plugin/plugin.json
  • .gitattributes
  • .github/workflows/ci.yml
  • .github/workflows/generator-generic-ossf-slsa3-publish.yml
  • .github/workflows/maintenance.yml
  • .github/workflows/release-announce.yml
  • .github/workflows/release.yml
  • .github/workflows/reusable-release.yml
  • .github/workflows/reusable-test.yml
  • .github/workflows/reusable-validate.yml
  • .github/workflows/supply-chain-watch.yml
  • .gitleaksignore
  • .opencode/commands/instinct-status.md
  • AGENTS.md
  • README.md
  • README.zh-CN.md
  • agent.yaml
  • commands/auto-update.md
  • commands/instinct-status.md
  • commands/learn-eval.md
  • commands/orch-review.md
  • commands/security-scan.md
  • commands/sessions.md
  • commands/skill-create.md
  • commands/skill-health.md
  • docs/COMMAND-REGISTRY.json
  • docs/design/ecc-pro-fleet-dashboard.md
  • docs/ja-JP/commands/auto-update.md
  • docs/ja-JP/commands/instinct-status.md
  • docs/ja-JP/commands/skill-health.md
  • docs/ja-JP/skills/gateguard/SKILL.md
  • docs/tr/commands/instinct-status.md
  • docs/tr/commands/sessions.md
  • docs/zh-CN/AGENTS.md
  • docs/zh-CN/README.md
  • docs/zh-CN/commands/auto-update.md
  • docs/zh-CN/commands/instinct-status.md
  • docs/zh-CN/commands/sessions.md
  • docs/zh-CN/commands/skill-health.md
  • docs/zh-CN/skills/gateguard/SKILL.md
  • ecc2/Cargo.toml
  • eslint.config.js
  • hooks/hooks.json
  • mcp-configs/mcp-servers.json
  • package.json
  • pyproject.toml
  • rules/README.md
  • rules/react-native/accessibility.md
  • rules/react-native/coding-style.md
  • rules/react-native/hooks.md
  • rules/react-native/patterns.md
  • rules/react-native/performance.md
  • rules/react-native/production-readiness.md
  • rules/react-native/security.md
  • rules/react-native/testing.md
  • scripts/hooks/doc-file-warning.js
  • scripts/hooks/gateguard-fact-force.js
  • scripts/hooks/mcp-health-check.js
  • scripts/hooks/plugin-hook-bootstrap.js
  • scripts/hooks/pre-compact.js
  • scripts/hooks/pre-write-doc-warn.js
  • scripts/hooks/session-end.js
  • scripts/hooks/session-start-bootstrap.js
  • scripts/lib/control-pane/proximity-viz.js
  • scripts/lib/control-pane/server.js
  • scripts/lib/llm-summary.js
  • scripts/lib/resolve-ecc-root.js
  • scripts/lib/resolve-formatter.js
  • scripts/lib/session-manager.js
  • scripts/release-approval-gate.js
  • scripts/release-video-suite.js
  • skills/backend-patterns/SKILL.md
  • skills/code-tour/SKILL.md
  • skills/coding-standards/SKILL.md
  • skills/continuous-learning-v2/agents/observer-loop.sh
  • skills/continuous-learning-v2/agents/observer.md
  • skills/continuous-learning-v2/hooks/observe.sh
  • skills/continuous-learning-v2/scripts/instinct-cli.py
  • skills/continuous-learning-v2/scripts/migrate-homunculus.sh
  • skills/continuous-learning-v2/scripts/test_parse_instinct.py
  • skills/delivery-gate/SKILL.md
  • skills/delivery-gate/hooks/quality-gate.py
  • skills/django-security/SKILL.md
  • skills/ecc-recipes/SKILL.md
  • skills/gateguard/SKILL.md
  • skills/growth-log/SKILL.md
  • skills/loop-design-check/SKILL.md
  • skills/mailtrap-email-integration/SKILL.md
  • skills/plan-orchestrate/SKILL.md
  • skills/prisma-patterns/SKILL.md
  • skills/react-native-patterns/SKILL.md
  • skills/security-review/SKILL.md
  • skills/tdd-workflow/SKILL.md
  • skills/team-builder/SKILL.md
  • src/llm/__init__.py
  • src/llm/cli/selector.py
  • src/llm/prompt/builder.py
  • src/llm/providers/claude.py
  • tests/ci/supply-chain-watch-workflow.test.js
  • tests/hooks/doc-file-warning.test.js
  • tests/hooks/hooks.test.js
  • tests/hooks/mcp-health-check.test.js
  • tests/hooks/migrate-homunculus-home-escape.test.js
  • tests/hooks/observe-signal-counter-race.test.js
  • tests/hooks/observe-signal-timeout.test.js
  • tests/hooks/observer-loop-archive.test.js
  • tests/hooks/observer-memory.test.js
  • tests/hooks/plugin-hook-bootstrap.test.js
  • tests/lib/command-plugin-root.test.js
  • tests/lib/llm-summary.test.js
  • tests/lib/resolve-ecc-root.test.js
  • tests/lib/session-manager.test.js
  • tests/scripts/control-pane.test.js
  • tests/scripts/instinct-cli-projects.test.js
  • tests/scripts/release-approval-gate.test.js
  • tests/scripts/release-video-suite.test.js
  • tests/test_builder.py
  • workflows/README.md
  • workflows/orch-review.workflow.js

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added an orch-review command/workflow for multi-dimension, fail-closed PR review with detailed verdict output.
    • Introduced a 3D “proximity” visualization and feed endpoint for the ECC Pro dashboard (HTML page + /api/proximity data).
  • Documentation

    • Published a draft ECC Pro + AgentShield security roadmap with “Top 5 — do now” priorities and PR/issue triage appendix.
    • Added an ECC Pro fleet dashboard design draft covering MVP scope, ingestion/query architecture, API contract, and redaction constraints.
    • Updated TDD workflow documentation to use package-manager/test-command placeholders and expanded Bun guidance.
  • Chores

    • Refreshed documented skill/command inventory counts across marketplace and READMEs.

Walkthrough

Adds an ECC Pro roadmap workflow and generated roadmap/design docs, plus broad updates to hooks, release-path helpers, docs, skills, workflows, and tests for shared root resolution, session summaries, control-pane proximity, and release-scoped paths.

Changes

ECC Pro roadmap and generated docs

Layer / File(s) Summary
Workflow schemas, agent phases, and synthesis
.claude/workflows/ecc-pro-security-roadmap.js
Defines workflow metadata, schemas, guardrails, four survey agents, four research agents, and a synthesis step that returns survey, research, and roadmap results.
Generated roadmap and dashboard design
docs/ECC-PRO-SECURITY-ROADMAP.md, docs/design/ecc-pro-fleet-dashboard.md
Adds the generated roadmap content and the fleet dashboard design covering scope, API contracts, data model, auth, storage, and build phases.

Hooks, runtime helpers, and release path logic

Layer / File(s) Summary
Hook bootstrap and ECC root resolution
.opencode/commands/instinct-status.md, commands/*, hooks/hooks.json, scripts/hooks/*, scripts/lib/resolve-ecc-root.js, scripts/lib/resolve-formatter.js
Switches root discovery to the shared resolver, updates hook bootstrap and shell handling, adds Windows quoting and shell fallback behavior, and preserves the new inline resolver contract across commands and hooks.
Session summaries and proximity control pane
scripts/hooks/pre-compact.js, scripts/hooks/session-end.js, scripts/lib/llm-summary.js, scripts/lib/control-pane/*
Adds LLM-backed session summaries and pre-compact/session-end handling, plus the proximity HTML renderer and /proximity / /api/proximity routes.
Release path helpers
scripts/release-approval-gate.js, scripts/release-video-suite.js
Derives release-scoped paths from package metadata and exports the new release path helpers.

Docs and skill guidance

Layer / File(s) Summary
Command docs and registry
commands/orch-review.md, docs/COMMAND-REGISTRY.json, README*, AGENTS.md, docs/*/commands/*, skills/*
Adds the new orch-review command docs, updates command counts and inventory text, refreshes session/root-resolution examples, and updates TDD, GateGuard, React Native, Prisma, Django, delivery-gate, loop-design, Mailtrap, and ecc-recipes guidance.
Skill and rules guidance
rules/README.md, rules/react-native/*, skills/*
Adds the React Native rules pack and related skill docs, including accessibility, coding style, hooks, patterns, performance, security, testing, and production-readiness guidance.

CI, dependencies, and packaging updates

Layer / File(s) Summary
Workflow pins and CI job changes
.github/workflows/*, tests/ci/supply-chain-watch-workflow.test.js
Bumps checkout/action pins, adds a Python test job, simplifies linting, and adds OMP release verification coverage.
Config and inventory metadata
.gitattributes, .gitleaksignore, .claude-plugin/*, package.json, pyproject.toml, ecc2/Cargo.toml, eslint.config.js, mcp-configs/mcp-servers.json
Updates line endings, ignore rules, plugin inventory counts, package/dependency versions, ESLint ignores, and MCP server config.

Regression and contract tests

Layer / File(s) Summary
Hook and runtime regression tests
tests/hooks/*
Adds regression coverage for doc warnings, hook bootstrap shell selection, MCP quoting, observer loop archive/timeout/counter behavior, session summaries, and session-start hook behavior.
Library and CLI contract tests
tests/lib/*, tests/scripts/*, tests/test_builder.py
Covers resolver helpers, llm-summary utilities, session-manager timestamps, control-pane endpoints, instinct CLI Python discovery, release script behavior, and prompt-builder formatting.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • affaan-m/ECC#2306 — The observer docs change removes the duplicated Scope Decision Guide table and points to the canonical skill table, matching the issue’s drift fix.

Possibly related PRs

  • affaan-m/ECC#1987 — Shares the hook bootstrap and inline resolver machinery updated here.
  • affaan-m/ECC#2013 — Touches the release-approval-gate path handling updated in this PR.
  • affaan-m/ECC#2059 — Overlaps the shared resolve-ecc-root-based /instinct-status resolution path.

Suggested reviewers: daltino

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main deliverable: a security roadmap document for ECC Pro and AgentShield that is revenue-focused.
Description check ✅ Passed The description directly addresses the changeset by explaining what was added (roadmap doc + workflow script), how it was generated (multi-agent research), and the strategic context behind it.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/ecc-pro-security-roadmap

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.

🔧 Biome (2.5.1)
workflows/orch-review.workflow.js

File contains syntax errors that prevent linting: Line 280: Illegal return statement outside of a function


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a docs-only MRR-biased product/security roadmap for ECC Pro and AgentShield, generated by a multi-agent workflow script. No production code is changed.

  • docs/ECC-PRO-SECURITY-ROADMAP.md — AI-generated roadmap covering 17 items across now/next/later horizons, with effort×impact scores and links to open PRs/issues. Stray XML generation artifacts remain at lines 237–238 (noted in a prior thread, not yet cleaned up).
  • docs/design/ecc-pro-fleet-dashboard.md — Draft architecture for a hosted "Sentry for agent security" surface. The fleet query endpoint returns \"ok\": false to indicate an unhealthy fleet, conflicting with the HTTP-success convention used by every other endpoint; absolute local filesystem paths also appear in the grounding-files appendix.
  • .claude/workflows/ecc-pro-security-roadmap.js — Reusable multi-agent orchestration script; schema and portability issues were flagged in prior threads.

Confidence Score: 4/5

Docs-only PR with no production code changes; safe to merge once the API contract inconsistency in the fleet dashboard is resolved.

The fleet dashboard design doc defines ok: false in the GET /v1/org/{orgId}/fleet response to indicate fleet health, while every other endpoint uses ok: true/false to indicate HTTP request success. Any implementation following the documented contract verbatim will mishandle healthy fleet queries that have posture issues.

docs/design/ecc-pro-fleet-dashboard.md — the fleet endpoint response shape and the grounding-files appendix both need attention before this document is used as an implementation spec.

Important Files Changed

Filename Overview
.claude/workflows/ecc-pro-security-roadmap.js Multi-agent orchestration workflow for roadmap generation. Schema issues and hardcoded ~/GitHub/ECC paths make it non-portable — both flagged in prior review threads.
docs/ECC-PRO-SECURITY-ROADMAP.md Roadmap document generated by the workflow script. Still contains stray XML artifact tags at lines 237-238 flagged in a prior thread.
docs/design/ecc-pro-fleet-dashboard.md New architecture design doc. Introduces an ambiguous ok: false response in the fleet query endpoint conflicting with the ok: true HTTP-success convention used by every other API endpoint. Also embeds absolute local filesystem paths in the grounding-files appendix.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CI as GitHub Action
    participant Watch as agentshield watch
    participant Runtime as PreToolUse hook
    participant GW as Ingestion Gateway
    participant DB as Postgres (Primary)
    participant TS as Time-Series Rollup
    participant API as Query API
    participant Dash as Dashboard (Next.js)
    participant Alerts as Routing/Alerts

    CI->>GW: POST /v1/ingest/scan
    GW-->>CI: 422 if not redacted / 409 if dedup
    GW->>DB: persist scan, finding, evidence_pack
    DB->>TS: rollup score_trend, drift_history

    Watch->>GW: POST /v1/ingest/drift
    GW->>DB: persist drift_event

    Runtime->>GW: POST /v1/ingest/runtime
    GW->>DB: persist runtime_event
    DB->>TS: rollup blocked_command_rate

    Dash->>API: "GET /v1/org/{orgId}/fleet"
    API-->>Dash: operatorReadback + fleet summary

    API->>Alerts: route reviewItems to Slack/Linear/GitHub
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CI as GitHub Action
    participant Watch as agentshield watch
    participant Runtime as PreToolUse hook
    participant GW as Ingestion Gateway
    participant DB as Postgres (Primary)
    participant TS as Time-Series Rollup
    participant API as Query API
    participant Dash as Dashboard (Next.js)
    participant Alerts as Routing/Alerts

    CI->>GW: POST /v1/ingest/scan
    GW-->>CI: 422 if not redacted / 409 if dedup
    GW->>DB: persist scan, finding, evidence_pack
    DB->>TS: rollup score_trend, drift_history

    Watch->>GW: POST /v1/ingest/drift
    GW->>DB: persist drift_event

    Runtime->>GW: POST /v1/ingest/runtime
    GW->>DB: persist runtime_event
    DB->>TS: rollup blocked_command_rate

    Dash->>API: "GET /v1/org/{orgId}/fleet"
    API-->>Dash: operatorReadback + fleet summary

    API->>Alerts: route reviewItems to Slack/Linear/GitHub
Loading

Reviews (2): Last reviewed commit: "docs(design): add hosted Pro fleet dashb..." | Re-trigger Greptile

Comment on lines +240 to +241
Notable gaps vs us (missing today):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Stray generation artifact leaked into rendered markdown

A bare </invoke> XML tag (and a </summary> closing tag appended to the preceding paragraph's last sentence) from the tool-calling XML envelope was not stripped before committing. Both will render as raw text in any markdown viewer. The </summary> tail appears at the end of the long competitor-gap-analysis paragraph just above, and </invoke> appears as a standalone line after it. Both should be deleted before this document is treated as canonical.

'CONSTRAINTS: research/triage only. Do NOT modify any code, do NOT open/close/merge PRs, do NOT post comments,',
'do NOT send any external message. Return findings as data only.',
'Brand it "ECC" (never "everything claude code"). AgentShield was FEATURED at a hackathon, never say it "won".',
'AgentShield npm package is "ecc-agentshield". Local clone: ~/GitHub/ECC/agentshield. ECC repo: affaan-m/ECC. AgentShield repo: affaan-m/agentshield.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Hardcoded personal local filesystem paths make the workflow non-portable. Any contributor on a different machine will get ENOENT errors from the agent() calls because ~/GitHub/ECC/agentshield and ~/GitHub/ECC/everything-claude-code almost certainly don't exist there. The paths should be expressed relative to the repository root or converted to environment-variable references that callers can override.

Suggested change
'AgentShield npm package is "ecc-agentshield". Local clone: ~/GitHub/ECC/agentshield. ECC repo: affaan-m/ECC. AgentShield repo: affaan-m/agentshield.',
`AgentShield npm package is "ecc-agentshield". Local clone: ${process.env.AGENTSHIELD_PATH ?? '~/GitHub/ECC/agentshield'}. ECC repo: affaan-m/ECC. AgentShield repo: affaan-m/agentshield.`,

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

relevanceToAgentShield: { type: 'string' },
proOpportunity: { type: 'string', description: 'how this could become ECC Pro / paid value' }
},
required: ['title', 'detail', 'source', 'gapVsUs', 'proOpportunity']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 relevanceToAgentShield is declared in the RESEARCH_SCHEMA properties but omitted from the required array. Agents can skip it silently and schema validation will pass — meaning the synthesis step may receive incomplete research objects where the key relevance mapping is absent without any error or warning.

Suggested change
required: ['title', 'detail', 'source', 'gapVsUs', 'proOpportunity']
required: ['title', 'detail', 'source', 'gapVsUs', 'relevanceToAgentShield', 'proOpportunity']

@@ -0,0 +1,189 @@
export const meta = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Workflow surface placement conflicts with AGENTS.md policy

AGENTS.md designates skills/ as the canonical workflow surface and states "New workflow contributions should land in skills/ first." Placing this file under .claude/workflows/ instead bypasses that convention. If .claude/workflows/ is intentionally a separate, framework-level runtime surface distinct from ECC skills, a brief comment in the file or a pointer in AGENTS.md would clarify the distinction for future contributors.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In @.claude/workflows/ecc-pro-security-roadmap.js:
- Around line 51-75: The RESEARCH_SCHEMA has an inconsistency where the property
relevanceToAgentShield is defined in the properties object of the findings items
but is missing from the required array. To fix this and align with the pattern
used in TRIAGE_SCHEMA, CAPABILITY_SCHEMA, and ROADMAP_SCHEMA where all defined
properties are required, add relevanceToAgentShield to the required array within
the findings items schema. The required array should include title, detail,
source, gapVsUs, relevanceToAgentShield, and proOpportunity.

In `@docs/ECC-PRO-SECURITY-ROADMAP.md`:
- Around line 125-132: The "Inline PR-comment review + autofix-PR via the
ecc-tools GitHub App" section contains an incorrect PR reference in the Linked
field. The current reference to PR `#2320` is actually linked to a different
feature (the 3D agent-airspace visualization) that is unrelated to PR comments
and autofix functionality. Either remove the incorrect "Linked: PR `#2320`"
reference or replace it with the correct PR number that actually corresponds to
the inline PR-comment review and autofix-PR work described in this section.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4c7c9cc9-8886-48b6-8bc6-5d84a4fb878f

📥 Commits

Reviewing files that changed from the base of the PR and between 71d22d0 and f698e3e.

📒 Files selected for processing (2)
  • .claude/workflows/ecc-pro-security-roadmap.js
  • docs/ECC-PRO-SECURITY-ROADMAP.md
📜 Review details
⏰ Context from checks skipped due to timeout. (29)
  • GitHub Check: Greptile Review
  • GitHub Check: Test (macos-latest, Node 20.x, bun)
  • GitHub Check: Test (macos-latest, Node 20.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 18.x, yarn)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, yarn)
  • GitHub Check: Test (windows-latest, Node 22.x, npm)
  • GitHub Check: Test (windows-latest, Node 18.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, npm)
  • GitHub Check: Test (windows-latest, Node 18.x, npm)
  • GitHub Check: Test (macos-latest, Node 20.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 22.x, yarn)
  • GitHub Check: Test (windows-latest, Node 20.x, yarn)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, bun)
  • GitHub Check: Test (windows-latest, Node 20.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, yarn)
  • GitHub Check: Test (macos-latest, Node 18.x, npm)
  • GitHub Check: Test (windows-latest, Node 20.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 22.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, bun)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, bun)
  • GitHub Check: Test (macos-latest, Node 22.x, yarn)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, yarn)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, pnpm)
  • GitHub Check: Coverage
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
🪛 Biome (2.5.0)
.claude/workflows/ecc-pro-security-roadmap.js

[error] 189-189: Illegal return statement outside of a function

(parse)

🪛 LanguageTool
docs/ECC-PRO-SECURITY-ROADMAP.md

[style] ~41-~41: Consider using a different verb for a more formal wording.
Context: ...#2273/#2246/#2312 docs, #2293 deps) and fix issue #2316 plan-orchestrate install de...

(FIX_RESOLVE)


[style] ~158-~158: Consider an alternative for the overused word “exactly”.
Context: ...lows with expiry and owner approval are exactly what org buyers pay seats for. Today po...

(EXACTLY_PRECISELY)


[style] ~190-~190: Consider an alternative for the overused word “exactly”.
Context: ...zero merge conflicts over Tailscale' is exactly what justifies per-seat team pricing. A...

(EXACTLY_PRECISELY)


[grammar] ~192-~192: Ensure spelling is correct
Context: ...graph (which agent invokes/delegates to which, with what inherited tools) and highlig...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~217-~217: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ime + optional sandbox/injection test). No live transcript/telemetry monitoring of...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~261-~261: Consider using a different verb for a more formal wording.
Context: ...more time triaging Snyk SCA alerts than fixing issues; CodeQL FP-heavy unit-test flags...

(FIX_RESOLVE)


[style] ~316-~316: The words ‘observations’ and ‘observe’ are quite similar. Consider replacing ‘observe’ with a different word.
Context: ...ilently drops in-flight observations in observe.sh | | merge | issue #2299 | bug: Pytho...

(VERB_NOUN_SENT_LEVEL_REP)

🔇 Additional comments (5)
.claude/workflows/ecc-pro-security-roadmap.js (2)

172-178: LGTM!


189-189: This return statement is valid for Claude's workflow runtime.

The file is a Claude workflow (in .claude/workflows/), not a standard Node.js module. Claude's workflow executor provides the export const meta metadata syntax and top-level functions like phase() and agent(). The top-level return at line 189 is intentional and correct—it returns the workflow result to the Claude execution environment. No changes needed.

			> Likely an incorrect or invalid review comment.
docs/ECC-PRO-SECURITY-ROADMAP.md (3)

8-16: LGTM!


36-43: LGTM!


1-348: LGTM!

Comment on lines +51 to +75
const RESEARCH_SCHEMA = {
type: 'object',
additionalProperties: false,
properties: {
topic: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
properties: {
title: { type: 'string' },
detail: { type: 'string' },
source: { type: 'string', description: 'URL, CVE id, or product name' },
gapVsUs: { type: 'string', enum: ['we-have-it', 'partial', 'missing'] },
relevanceToAgentShield: { type: 'string' },
proOpportunity: { type: 'string', description: 'how this could become ECC Pro / paid value' }
},
required: ['title', 'detail', 'source', 'gapVsUs', 'proOpportunity']
}
},
summary: { type: 'string' }
},
required: ['topic', 'findings', 'summary']
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Schema inconsistency: relevanceToAgentShield is optional while other fields are required.

In RESEARCH_SCHEMA, the field relevanceToAgentShield appears in properties (line 66) but is omitted from the required array (line 69). All other schemas (TRIAGE_SCHEMA, CAPABILITY_SCHEMA, ROADMAP_SCHEMA) require every defined property. This breaks the pattern and makes relevanceToAgentShield silently optional, which may allow research agents to skip relevance assessments.

🔧 Proposed fix to make the field required
     },
     summary: { type: 'string' }
   },
-  required: ['topic', 'findings', 'summary']
+  required: ['topic', 'findings', 'summary'],
+  patternProperties: {
+    '^findings$': {
+      items: {
+        required: ['title', 'detail', 'source', 'gapVsUs', 'relevanceToAgentShield', 'proOpportunity']
+      }
+    }
+  }
 };

Alternatively, if relevanceToAgentShield is intentionally optional, document why it deviates from the all-required pattern used in the other three schemas.

📝 Committable suggestion

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

Suggested change
const RESEARCH_SCHEMA = {
type: 'object',
additionalProperties: false,
properties: {
topic: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
properties: {
title: { type: 'string' },
detail: { type: 'string' },
source: { type: 'string', description: 'URL, CVE id, or product name' },
gapVsUs: { type: 'string', enum: ['we-have-it', 'partial', 'missing'] },
relevanceToAgentShield: { type: 'string' },
proOpportunity: { type: 'string', description: 'how this could become ECC Pro / paid value' }
},
required: ['title', 'detail', 'source', 'gapVsUs', 'proOpportunity']
}
},
summary: { type: 'string' }
},
required: ['topic', 'findings', 'summary']
};
const RESEARCH_SCHEMA = {
type: 'object',
additionalProperties: false,
properties: {
topic: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
properties: {
title: { type: 'string' },
detail: { type: 'string' },
source: { type: 'string', description: 'URL, CVE id, or product name' },
gapVsUs: { type: 'string', enum: ['we-have-it', 'partial', 'missing'] },
relevanceToAgentShield: { type: 'string' },
proOpportunity: { type: 'string', description: 'how this could become ECC Pro / paid value' }
},
required: ['title', 'detail', 'source', 'gapVsUs', 'relevanceToAgentShield', 'proOpportunity']
}
},
summary: { type: 'string' }
},
required: ['topic', 'findings', 'summary']
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/workflows/ecc-pro-security-roadmap.js around lines 51 - 75, The
RESEARCH_SCHEMA has an inconsistency where the property relevanceToAgentShield
is defined in the properties object of the findings items but is missing from
the required array. To fix this and align with the pattern used in
TRIAGE_SCHEMA, CAPABILITY_SCHEMA, and ROADMAP_SCHEMA where all defined
properties are required, add relevanceToAgentShield to the required array within
the findings items schema. The required array should include title, detail,
source, gapVsUs, relevanceToAgentShield, and proOpportunity.

Comment on lines +125 to +132
### Inline PR-comment review + autofix-PR via the ecc-tools GitHub App

- **Area:** agentshield | **Effort:** M | **Impact:** high
- **Linked:** PR #2320
- **MRR angle:** Sticky inline PR comments + one-click fix PRs are now table stakes (Aikido, DryRun, Pixee) and are the GitHub-native paid surface that converts. The GitHub App already exists as the delivery vehicle; monetize PR-time review + autofix-PR as the paid tier.

Today the GitHub Action fails CI and emits SARIF (lands in the Security tab) but does not post sticky inline PR comments keyed to changed lines, and autofix is local-CLI only. Add per-line PR comments with one-click 'apply fix' that commits the existing remediation to the PR branch, plus auto-fix-PR generation. Differentiate from CodeRabbit/Greptile by bundling the agent-proximity / merge-conflict-prevention angle competitors lack.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Incorrect linked PR reference.

Line 128 claims this item is "Linked: PR #2320", but PR #2320 is the 3D agent-airspace visualization (see line 278 of the ECC triage table and the NOW item at lines 84-91). The "Inline PR-comment review + autofix-PR via the ecc-tools GitHub App" item describes adding PR comments and autofix-PR generation, which is unrelated to the 3D viz.

This appears to be a cross-reference error in the generated roadmap.

🔧 Proposed fix
 ### Inline PR-comment review + autofix-PR via the ecc-tools GitHub App
 
 - **Area:** agentshield | **Effort:** M | **Impact:** high
-- **Linked:** PR `#2320`
+- **Linked:** (no open PR/issue yet)
 - **MRR angle:** Sticky inline PR comments + one-click fix PRs are now table stakes (Aikido, DryRun, Pixee) and are the GitHub-native paid surface that converts. The GitHub App already exists as the delivery vehicle; monetize PR-time review + autofix-PR as the paid tier.
📝 Committable suggestion

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

Suggested change
### Inline PR-comment review + autofix-PR via the ecc-tools GitHub App
- **Area:** agentshield | **Effort:** M | **Impact:** high
- **Linked:** PR #2320
- **MRR angle:** Sticky inline PR comments + one-click fix PRs are now table stakes (Aikido, DryRun, Pixee) and are the GitHub-native paid surface that converts. The GitHub App already exists as the delivery vehicle; monetize PR-time review + autofix-PR as the paid tier.
Today the GitHub Action fails CI and emits SARIF (lands in the Security tab) but does not post sticky inline PR comments keyed to changed lines, and autofix is local-CLI only. Add per-line PR comments with one-click 'apply fix' that commits the existing remediation to the PR branch, plus auto-fix-PR generation. Differentiate from CodeRabbit/Greptile by bundling the agent-proximity / merge-conflict-prevention angle competitors lack.
### Inline PR-comment review + autofix-PR via the ecc-tools GitHub App
- **Area:** agentshield | **Effort:** M | **Impact:** high
- **Linked:** (no open PR/issue yet)
- **MRR angle:** Sticky inline PR comments + one-click fix PRs are now table stakes (Aikido, DryRun, Pixee) and are the GitHub-native paid surface that converts. The GitHub App already exists as the delivery vehicle; monetize PR-time review + autofix-PR as the paid tier.
Today the GitHub Action fails CI and emits SARIF (lands in the Security tab) but does not post sticky inline PR comments keyed to changed lines, and autofix is local-CLI only. Add per-line PR comments with one-click 'apply fix' that commits the existing remediation to the PR branch, plus auto-fix-PR generation. Differentiate from CodeRabbit/Greptile by bundling the agent-proximity / merge-conflict-prevention angle competitors lack.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ECC-PRO-SECURITY-ROADMAP.md` around lines 125 - 132, The "Inline
PR-comment review + autofix-PR via the ecc-tools GitHub App" section contains an
incorrect PR reference in the Linked field. The current reference to PR `#2320` is
actually linked to a different feature (the 3D agent-airspace visualization)
that is unrelated to PR comments and autofix functionality. Either remove the
incorrect "Linked: PR `#2320`" reference or replace it with the correct PR number
that actually corresponds to the inline PR-comment review and autofix-PR work
described in this section.

… security)

Implementation-ready architecture for the flagship 'next' roadmap item: a
hosted, multi-repo agent-security posture dashboard built on the existing
ecc-agentshield primitives (evidence-pack bundleDigest + operatorReadback,
watch/drift DriftResult, runtime NDJSON, baseline diff, policy promotion).
Covers free-vs-Pro scope, ingestion/query API grounded in real field names,
data model + time-series rollups, auth/RBAC + redaction guarantees, MVP build
order, and pricing hooks. Companion to ECC-PRO-SECURITY-ROADMAP.md.
@ecc-tools

ecc-tools Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

Inline comments:
In `@docs/design/ecc-pro-fleet-dashboard.md`:
- Around line 121-127: The ciContext object currently only identifies the
repository by slug in the "repository" field, but the downstream data model keys
repos on stable GitHub repo IDs, which can lead to duplicate repos when slugs
are renamed. Add a "repositoryId" field to the ciContext object containing the
stable GitHub repository ID, or alternatively document the complete fallback
keying strategy that explains how the system will handle repo slug changes and
maintain referential integrity.
- Line 97: The runtime event idempotency key definition using `(repo_id,
timestamp, tool, decision)` is insufficient and will cause collisions for
distinct events in the same batch with millisecond timestamps and repeated
decisions. Update the idempotency key specification to include `sessionId` plus
the full entry payload (or a server-issued event UUID) to ensure that retries
properly deduplicate without losing real telemetry data. This change should be
reflected in the runtime ingestion idempotency section and any other locations
where the idempotency key format is defined or referenced (including the
sections noted as also applying to this issue).
- Around line 199-221: The GET /v1/org/{orgId}/fleet endpoint accepts orgId as a
user-supplied path parameter, creating a confused-deputy security risk. Remove
the {orgId} path parameter from the route definition and instead derive the
orgId from the bearer token claims in the handler. Update the route to GET
/v1/fleet and ensure the handler extracts the orgId exclusively from the token
claims to enforce that the API only operates on the organization authenticated
in the bearer token. Apply this same fix to the other endpoint mentioned at
lines 259-266.
- Around line 144-145: The server-side guard logic that handles bundle digest
validation currently stores mismatched bundles by marking them with `integrity:
"mismatch"`, which allows poisoned data to flow into the rollup pipeline.
Instead of storing these failed scans, reject the request with an appropriate
HTTP status code (such as 400 or 422) when `expectedBundleDigest` is present and
differs from the actual `bundleDigest`. This ensures digest mismatches are
caught and rejected at the boundary before they can contaminate the normal
rollup path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f8092f58-0391-4fc8-9b1b-e4885405ee35

📥 Commits

Reviewing files that changed from the base of the PR and between f698e3e and a26a0d5.

📒 Files selected for processing (1)
  • docs/design/ecc-pro-fleet-dashboard.md
📜 Review details
⏰ Context from checks skipped due to timeout. (29)
  • GitHub Check: Test (windows-latest, Node 20.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 20.x, npm)
  • GitHub Check: Test (macos-latest, Node 22.x, npm)
  • GitHub Check: Test (windows-latest, Node 18.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, yarn)
  • GitHub Check: Test (windows-latest, Node 18.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 22.x, yarn)
  • GitHub Check: Test (windows-latest, Node 18.x, yarn)
  • GitHub Check: Test (macos-latest, Node 20.x, bun)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, yarn)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, bun)
  • GitHub Check: Test (macos-latest, Node 20.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 22.x, npm)
  • GitHub Check: Test (windows-latest, Node 22.x, npm)
  • GitHub Check: Test (windows-latest, Node 22.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, npm)
  • GitHub Check: Test (macos-latest, Node 18.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, yarn)
  • GitHub Check: Test (macos-latest, Node 22.x, pnpm)
  • GitHub Check: Test (ubuntu-latest, Node 20.x, bun)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, npm)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, bun)
  • GitHub Check: Test (ubuntu-latest, Node 18.x, pnpm)
  • GitHub Check: Test (windows-latest, Node 20.x, yarn)
  • GitHub Check: Coverage
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
🪛 LanguageTool
docs/design/ecc-pro-fleet-dashboard.md

[uncategorized] ~237-~237: The official name of this software platform is spelled with a capital “H”.
Context: ...e ISO-8601 UTC. - org: id, name, github_org_login, plan (team | `enterpris...

(GITHUB)


[uncategorized] ~238-~238: The official name of this software platform is spelled with a capital “H”.
Context: ...ull_name(e.g.acme/agent-platform), github_repo_id(fromEvidencePackGitHubConte...

(GITHUB)


[uncategorized] ~260-~260: The official name of this software platform is spelled with a capital “H”.
Context: ...rows are children of exactly one org; github_repo_id from `EvidencePackGitHubContex...

(GITHUB)


[uncategorized] ~274-~274: The official name of this software platform is spelled with a capital “H”.
Context: ...ildReplacements(coverssk-, gh*, github_pat, glpat-, npm_, AKIA, JWT e...

(GITHUB)


## 4. API Contract

All endpoints are authenticated with an org-scoped API token (header `Authorization: Bearer eccp_...`). Request/response shapes reuse the real field names from the CLI so the producers do not need a translation layer. Ingestion is idempotent keyed on `bundleDigest` (scans) or `(repo_id, timestamp, tool, decision)` hash (runtime).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make runtime idempotency key include the full event identity.

(repo_id, timestamp, tool, decision) will collide for distinct runtime events in the same batch/session, especially with millisecond timestamps and repeated allow/block decisions. Key on sessionId plus the full entry payload (or a server-issued event UUID) so retries dedupe without dropping real telemetry.

♻️ Proposed fix
- Ingestion is idempotent keyed on `(repo_id, timestamp, tool, decision)` hash (runtime).
+ Ingestion is idempotent keyed on `sessionId` plus a hash of the full runtime entry payload.

Also applies to: 148-167

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

In `@docs/design/ecc-pro-fleet-dashboard.md` at line 97, The runtime event
idempotency key definition using `(repo_id, timestamp, tool, decision)` is
insufficient and will cause collisions for distinct events in the same batch
with millisecond timestamps and repeated decisions. Update the idempotency key
specification to include `sessionId` plus the full entry payload (or a
server-issued event UUID) to ensure that retries properly deduplicate without
losing real telemetry data. This change should be reflected in the runtime
ingestion idempotency section and any other locations where the idempotency key
format is defined or referenced (including the sections noted as also applying
to this issue).

Comment on lines +121 to +127
"ciContext": {
"provider": "github-actions",
"repository": "acme/agent-platform",
"workflow": "security.yml",
"runId": "1182334455",
"sha": "4c1d9ab"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a stable repo identifier to the ingest contract.

The request only carries the repo slug, but the data model later keys repo on a stable GitHub repo ID. Slugs can rename, so this will create duplicate repos or brittle backfills. Add repositoryId to ciContext or spell out the fallback keying strategy.

♻️ Proposed fix
   "ciContext": {
     "provider": "github-actions",
     "repository": "acme/agent-platform",
+    "repositoryId": "123456789",
     "workflow": "security.yml",
     "runId": "1182334455",
     "sha": "4c1d9ab"
   },

Also applies to: 237-239

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

In `@docs/design/ecc-pro-fleet-dashboard.md` around lines 121 - 127, The ciContext
object currently only identifies the repository by slug in the "repository"
field, but the downstream data model keys repos on stable GitHub repo IDs, which
can lead to duplicate repos when slugs are renamed. Add a "repositoryId" field
to the ciContext object containing the stable GitHub repository ID, or
alternatively document the complete fallback keying strategy that explains how
the system will handle repo slug changes and maintain referential integrity.

Comment on lines +144 to +145
Server-side guards: reject with `422` if `redacted !== true` (hosted tenants must never store unredacted bundles), and reject with `409 deduped` echo if `bundleDigest` already ingested for that repo. If `expectedBundleDigest` is present and differs from `bundleDigest`, mark `integrity: "mismatch"` on the stored scan.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject digest mismatches instead of storing them as normal scans.

bundleDigest is the idempotency key and feeds downstream rollups. Persisting a mismatched payload with integrity: "mismatch" risks poisoning history instead of stopping bad input at the boundary. Reject or quarantine the record before it reaches the normal rollup path.

🔒 Proposed fix
- If `expectedBundleDigest` is present and differs from `bundleDigest`, mark `integrity: "mismatch"` on the stored scan.
+ If `expectedBundleDigest` differs from `bundleDigest`, reject the request (or quarantine it outside normal rollups).
📝 Committable suggestion

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

Suggested change
Server-side guards: reject with `422` if `redacted !== true` (hosted tenants must never store unredacted bundles), and reject with `409 deduped` echo if `bundleDigest` already ingested for that repo. If `expectedBundleDigest` is present and differs from `bundleDigest`, mark `integrity: "mismatch"` on the stored scan.
Server-side guards: reject with `422` if `redacted !== true` (hosted tenants must never store unredacted bundles), and reject with `409 deduped` echo if `bundleDigest` already ingested for that repo. If `expectedBundleDigest` differs from `bundleDigest`, reject the request (or quarantine it outside normal rollups).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/ecc-pro-fleet-dashboard.md` around lines 144 - 145, The
server-side guard logic that handles bundle digest validation currently stores
mismatched bundles by marking them with `integrity: "mismatch"`, which allows
poisoned data to flow into the rollup pipeline. Instead of storing these failed
scans, reject the request with an appropriate HTTP status code (such as 400 or
422) when `expectedBundleDigest` is present and differs from the actual
`bundleDigest`. This ensures digest mismatches are caught and rejected at the
boundary before they can contaminate the normal rollup path.

Comment on lines +199 to +221
`GET /v1/org/{orgId}/fleet`

Response reuses the `EvidencePackFleetInspectionResult` `operatorReadback` shape so the dashboard and the existing `evidence-pack fleet` consumers share one contract:
```json
{
"ok": false,
"requiresAttention": true,
"summary": { "totalPacks": 12, "verifiedPacks": 11, "invalidPacks": 1, "critical": 2, "high": 9, "policyFailures": 3, "baselineRegressions": 2, "riskyPackages": 5 },
"operatorReadback": {
"status": "blocked",
"ready": false,
"requiresApproval": true,
"digest": "sha256:aa17...",
"reviewItemCount": 5,
"blockingItemCount": 2,
"ownerCount": 3,
"owners": ["acme/agent-platform security owner"],
"routesRequiringApproval": ["policy-review", "security-blocker"],
"approvalIds": ["agsr_2b1c8f0d9e7a4c11"],
"nextAction": "Route review items to listed owners and attach approval before promotion."
}
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't make tenant identity user-supplied on fleet queries.

This route takes {orgId} from the caller, but section 6 says query APIs must only operate on the org in the bearer token. Unless the handler explicitly rejects mismatches, this is a confused-deputy risk. Prefer deriving the org from token claims and removing the path parameter.

🛡️ Proposed fix
- GET /v1/org/{orgId}/fleet
+ GET /v1/org/fleet

Also applies to: 259-266

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

In `@docs/design/ecc-pro-fleet-dashboard.md` around lines 199 - 221, The GET
/v1/org/{orgId}/fleet endpoint accepts orgId as a user-supplied path parameter,
creating a confused-deputy security risk. Remove the {orgId} path parameter from
the route definition and instead derive the orgId from the bearer token claims
in the handler. Update the route to GET /v1/fleet and ensure the handler
extracts the orgId exclusively from the token claims to enforce that the API
only operates on the organization authenticated in the bearer token. Apply this
same fix to the other endpoint mentioned at lines 259-266.

affaan-m and others added 22 commits June 25, 2026 16:45
…#2320)

Adds the Layer 4 observability view to the control pane: a self-contained,
dependency-free 3D point-cloud of the agent airspace (positions from the
proximity embedding, sized by working set, colored by collision risk, links
for converging pairs) plus an XSS-safe advisory panel that polls every 5s.

- proximity-viz.js: renderProximityVizHtml() (canvas projection, no external JS)
- server.js: GET /proximity (page) + GET /api/proximity (snapshot.proximity feed)
- test: asserts both routes serve and the feed carries positions/links/advisories
* fix(clv2): escape $HOME before pgrep -f in migrate-homunculus.sh

pgrep -f treats its argument as an extended regular expression, but the
running-observer guard interpolated $HOME unescaped. Paths containing regex
metacharacters (e.g. /home/user.name, /home/c++dev, /home/user (work)) made the
match over-broad or invalid, causing either a false negative (live observer
missed, migration proceeds and risks registry corruption) or a false positive
(migration blocked unnecessarily).

Escape the ERE metacharacters in $HOME via sed before building the pattern so
the home prefix is matched literally while the trailing .*observer-loop\.sh
regex is preserved. Portable across BSD and GNU sed.

Fixes #2301

* test(clv2): add regression test for migrate-homunculus.sh $HOME escaping

Guards the #2301 fix: extracts the script's sed escaping command and asserts
the resulting pgrep -f pattern matches the literal home path while no longer
over-matching a regex-expanded decoy (HOME=/home/user.name must not match
/home/userXname). Also pins that the guard uses escaped_home rather than $HOME
directly. Follows the existing clv2 shell-test convention in
tests/hooks/observe-entrypoint-allowlist.test.js.

Refs #2301

* test(clv2): skip migrate-homunculus escaping test on Windows

The test relies on POSIX bash/sed/grep -E semantics, which differ on the
Windows CI runners. Guard with the same process.platform === 'win32' early
exit used by tests/hooks/observe-subdirectory-detection.test.js so the
bash-dependent assertions only run on POSIX platforms.

Refs #2301
…#2323)

Two security-priority fixes in continuous-learning-v2/scripts/instinct-cli.py:

- #2294: _write_registry wrote projects.json without the advisory lock that
  _update_registry holds, so concurrent 'projects delete/gc/merge' could race an
  observe-time update and corrupt the registry. Extract the lock into a shared
  _registry_lock() context manager and use it in both writers.

- #2297: _remove_project_storage called shutil.rmtree on PROJECTS_DIR/project_id
  with no containment check. Add defense-in-depth: resolve the path and refuse to
  delete anything that is not strictly inside PROJECTS_DIR (or is the root
  itself), so a relaxed validator or future caller can never cause an
  arbitrary-directory delete.

Adds 5 pytest regression tests (atomic write under lock, contained delete,
missing-dir no-op, traversal refused, root refused). Node integration suite
(tests/scripts/instinct-cli-projects.test.js) green 9/9.
* feat(workflows): add orch-review native Workflow pilot

Port orch-pipeline Phase 5 (Review) to a native Claude Code Workflow
script. The gated outer loop stays in the main conversation; this script
owns only the autonomous review+verify segment between the two human
gates:

1. Review — reviewers fan out in parallel: ecc:code-reviewer always,
   ecc:<language>-reviewer when args.language maps, ecc:security-reviewer
   when the orch-pipeline security trigger matches the diff/paths.
2. Dedup — merge findings across dimensions keyed on the normalized
   evidence snippet, since independent reviewers flag the same line.
3. Verify — each unique CRITICAL/HIGH finding goes to an independent
   adversarial verifier; MEDIUM/LOW pass through as advisory.

The Review->Verify barrier is deliberate: deduping before verification
stops the verifier running N times on the same bug (local testing: 11
raw findings collapsed to 4 unique, ~halving verifier cost).

Existing ECC reviewer subagents are reused via agentType; reviewer
output is validated by JSON schema. args is accepted as an object or a
JSON-encoded string.

- workflows/orch-review.workflow.js — the workflow script
- workflows/README.md — invocation contract, returns shape, follow-ups

CI lint is scoped to scripts/ and tests/, so the script (validated with
node --check) and the README (passes markdownlint) are untouched.

* fix(workflows): fail closed on invalid args and lost review dimensions

Addresses the two safety findings from the PR bot review:

1. Lost review dimension (Greptile P1 / CodeRabbit Major): a reviewer
   agent that returns null or rejects was silently dropped by
   filter(Boolean), so an unreviewed security dimension could still
   return APPROVE. Each dimension's outcome is now captured; failures
   land in failedDimensions and force CHANGES_REQUESTED (incomplete).

2. Invalid args (CodeRabbit Major): an empty diff returned APPROVE and
   bad JSON / non-array changedFiles threw inconsistently. Input is now
   validated up front and rejected with a clear error — the gate fails
   closed instead of approving an unreviewed payload.

Docs (header contract + README) updated for the new return fields
(incomplete, failedDimensions, stats.failed). Remaining bot nits
(evidence minLength, verify-label collision, verified->confirmed
rename, contract drift) deferred as follow-ups.

* fix(workflows): address remaining orch-review review nits

Follow-up to the bot review (deferred items from the safety pass):

- evidence: require minLength 1 in the schema, and fall back to a
  title+line dedup key when evidence is empty, so empty-evidence
  findings in one file no longer collapse onto a single key and drop
  (CodeRabbit).
- verify label: include a slice of the normalized evidence so two
  CRITICAL/HIGH findings from the same file get distinct labels and do
  not alias under resumability (Greptile).
- stats.verified -> stats.confirmed to match the "confirmed" wording
  used in the log and avoid ambiguity vs the refuted count (Greptile);
  header contract and README updated to match.

Verified by running the workflow on a synthetic vulnerable diff:
dedup 12 raw -> 5 unique, stats.confirmed populated, fail-closed fields
(incomplete/failedDimensions) intact.

* fix(workflows): harden verify stage and diff-only verification

Addresses the second-round bot review:

- Verify stage now has the same failure guard as the review stage: a
  rejected verifier no longer nulls out its slot (which crashed the
  later filter). A null return is treated as unconfirmed; a rejection
  keeps the finding as blocking (fail closed) so an unverifiable
  CRITICAL is never silently demoted to advisory (CodeRabbit @221).
- verifyPrompt now instructs the skeptic to judge solely from the
  provided diff text and not to refute merely because the referenced
  file is absent from the working tree (the diff may be an unapplied
  PR). Fixes the false-refute seen when testing on a synthetic diff.

CodeRabbit @81 (evidence minLength) was already addressed in the prior
commit; this is a stale re-post on the unresolved thread.

* fix(workflows): keep unverifiable blockers blocking; stop leaking error text

Second-round bot review (CodeRabbit):

- @218 Treat a null/failed verifier as `unverified`, not refuted. A
  terminal verifier failure or skip no longer demotes a CRITICAL/HIGH
  to advisory; it stays in `blocking` tagged "could not be verified"
  (fail closed). Only a genuine isReal=false verdict is refuted. Adds
  stats.unverified.
- @189 Do not return raw subagent error text. Review/verify failures
  now log the raw message for operators and return only a bounded label
  (failedDimensions[].error = "review agent failed").

Stale re-posts this round (@81 evidence minLength, @224 verify guard)
were already fixed in prior commits.

* docs(workflows): enumerate bounded failedDimensions.error labels

CodeRabbit (trivial): the public contract implied callers get
human-readable error text, but the implementation returns only bounded
labels. Enumerate them in the README returns block.
* Add memxus configuration to mcp-servers.json

Added configuration for Memxus service with API key placeholder and description.

* Revise description in mcp-servers.json

Updated the description to include a note about reviewing stored memories to prevent prompt-injection.

* Update description in mcp-servers.json

Update description in mcp-servers.json
…bserver.md with minor drift (#2366)

#2306

Co-authored-by: angadsingh7666 <[email protected]>
Replace invalid default model IDs (e.g. claude-sonnet-4-7) with current
claude-sonnet-4-6, claude-opus-4-8, and claude-haiku-4-5. Route system
messages to the API system field, enable ephemeral prompt caching, omit
temperature for Opus 4.7/4.8, and surface cache usage metrics. Update the
CLI model picker to match.

Co-authored-by: Vladimir Đuranović <[email protected]>
Co-authored-by: Cursor <[email protected]>
- resolve-formatter: stop findProjectRoot walk before os.homedir() to
  avoid mistaking global dotfiles (e.g. ~/.prettierrc) for a project root
- instinct-cli-projects: detect python3/python binary at runtime; skip
  gracefully when Python 3 is unavailable instead of crashing with null status
- command-registry: regenerate COMMAND-REGISTRY.json (was stale)

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
#2343)

On Windows, when a bare-name MCP server command (e.g. codesys-mcp-sp21-plus)
falls back to the .cmd candidate, the probe sets shell:true to work around
Node 18.20+ CVE-2024-27980. However, passing an args array alongside
shell:true causes Node to concatenate the tokens without quoting (DEP0190),
so an arg containing a space (e.g. --codesys-path "C:\Program Files\...") is
re-split by cmd.exe at every space boundary. The child process receives a
truncated path, fails to launch, and the probe declares the server unavailable,
falsely blocking every MCP tool call to that server.

Fix: add a quoteWin() helper that double-quotes any token containing whitespace
or cmd metacharacters. In the useShell branch, build a single properly-quoted
command line string and pass it as the sole argument to spawn() with no separate
args array. The else branch (shell:false, all non-.cmd commands) is unchanged.

Regression test added: on Windows, creates a .cmd shim that echoes its first
positional argument to stderr, probes it with a space-containing path arg, and
asserts the probe succeeds and the arg was not split at the space boundary.

Co-authored-by: Karstein Phobic Nyvold Kvistad <[email protected]>
#2358)

* fix(hooks): guard doc-file-warning stdin listeners behind require.main

doc-file-warning.js registered process.stdin data/end listeners at module
scope while also exporting run(). run-with-flags.js require()s any hook that
exports run() for its in-process fast path, so importing this hook attached
stray stdin listeners to the dispatcher process, corrupting the PreToolUse
stdout JSON contract. This is the exact failure run-with-flags' own SAFETY
comment warns about, and 24 sibling hooks already guard against it.

- Move the stdin entrypoint into main() and gate it behind require.main === module
- pre-write-doc-warn.js now calls main() explicitly instead of relying on the
  import side effect
- Add regression tests: require() attaches no stdin listeners, run()/main()
  stay exported, and the pre-write-doc-warn shim still warns

* docs(hooks): add JSDoc for doc-file-warning main() entrypoint

Satisfies the docstring-coverage pre-merge check; documents the stdin
entrypoint and why it must not run on require().
…ccumulation (#2346)

* fix(windows): prefer PowerShell over bash to prevent zombie process accumulation

On Windows, ECC hook scripts were spawning bash.exe (MSYS2/Git Bash) on
every tool use via findShellBinary(). These processes were not reaped by
Windows, causing 40+ zombie bash.exe/conhost.exe processes per session with
noticeable system lag.

Changes to scripts/hooks/plugin-hook-bootstrap.js:
- Add isPowerShellBin(bin) helper: basename-based detection so full paths
  like C:\Windows\...\powershell.exe are handled correctly
- findShellBinary(): check BASH env var first (preserves escape hatch),
  then on win32 probe pwsh.exe -> powershell.exe -> bash.exe -> bash;
  use correct probe args per shell type; cache result in _cachedShell
- findBashBinary(): separate cached bash-only finder used by spawnShell
  .sh fallback; skips PowerShell binaries even if BASH points to one
- spawnShell(): use isPowerShellBin() to select -NoProfile -NonInteractive
  -File args for PowerShell; .sh scripts fall back to findBashBinary()
  with a skip-warning if no bash found on Windows

observe-runner.js is intentionally unchanged: it always invokes observe.sh
which is bash-only; routing it through PowerShell would silently break it.
The observe.sh -> observe.js migration is tracked separately.

Fixes #2345

* fix(windows): address CodeRabbit and Greptile review comments

- Add timeout: 30000 to all spawnSync probe calls in findShellBinary and
  findBashBinary to prevent hangs on broken/stalled shell candidates
- Add -ExecutionPolicy Bypass to PowerShell -File invocation to fix
  execution on machines with the default Restricted policy (Win10/11)
- Add PowerShell availability skip guard to PS selection test (mirrors
  existing bash skip guard)
- Fix no-bash test to keep PowerShell on PATH so the .sh fallback branch
  is actually exercised rather than hitting shell-unavailable early exit

* test: add timeout to spawnSync probes in Windows test skip guards

---------

Co-authored-by: Christopher J Diamond <[email protected]>
Replace mechanical text extraction in session-end.js and pre-compact.js
with LLM-generated summaries using `claude -p`. Summaries now capture
design decisions, resolved bugs, changed files, and carry-over context
rather than just truncated user message snippets.

- Add scripts/lib/llm-summary.js: generateSessionSummary, extractConversationText,
  getContextRemainingPct, getContextThreshold, getLLMModel
- Update scripts/hooks/session-end.js: trigger LLM when context < 20% or
  every 50 messages (env-configurable via ECC_LLM_SUMMARY_*)
- Update scripts/hooks/pre-compact.js: generate LLM summary right before
  compaction and write it to the active session .tmp file
- Add tests/lib/llm-summary.test.js: 18 unit tests
- Update tests/hooks/hooks.test.js: 3 integration tests for new behaviour

Recursion guard: sets ECC_SKIP_LLM_SUMMARY=1 in subprocess env so Stop
hooks fired by the claude -p subprocess do not re-enter summarisation.
Requires no ANTHROPIC_API_KEY — reuses Claude Code's own authentication.

Co-authored-by: Hiroshi Tanaka <[email protected]>
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
…2329)

Updates the requirements on [anthropic](https://github.com/anthropics/anthropic-sdk-python) to permit the latest version.
- [Release notes](https://github.com/anthropics/anthropic-sdk-python/releases)
- [Changelog](https://github.com/anthropics/anthropic-sdk-python/blob/main/CHANGELOG.md)
- [Commits](anthropics/anthropic-sdk-python@v0.25.0...v0.111.0)

---
updated-dependencies:
- dependency-name: anthropic
  dependency-version: 0.111.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](actions/checkout@v6.0.3...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ows/generator_generic_slsa3.yml (#2330)

Bumps [slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml](https://github.com/slsa-framework/slsa-github-generator) from 1.4.0 to 2.1.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](slsa-framework/slsa-github-generator@68bad40...f7dd8c5)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [cron](https://github.com/zslayton/cron) from 0.16.0 to 0.17.0.
- [Release notes](https://github.com/zslayton/cron/releases)
- [Commits](https://github.com/zslayton/cron/commits)

---
updated-dependencies:
- dependency-name: cron
  dependency-version: 0.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pytest@8.0.0...9.1.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 9.1.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](python/mypy@v1.10.0...v2.1.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 2.1.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
carloscarvallo and others added 24 commits June 29, 2026 18:38
…-not-found (#2273)

The code-tour skill mentioned the CodeTour 'ref' field only in an example,
with no explanation of its behavior. CodeTour resolves each step's file
content from the git revision named by 'ref' (not the working tree) whenever
ref differs from HEAD, so any file that does not exist at that revision fails
to open with 'The editor could not be opened because the file was not found'
- even though the file is present on disk.

This bit a generated PR tour where ref was set to the base branch (develop):
every file ADDED by the PR is absent on the base, so all new-file steps 404'd
while the tour tree and comments still rendered, making the cause non-obvious.

Adds a 'The ref Field' section explaining the resolution behavior and the
rule that PR tours must pin ref to the branch head (never the base), plus a
validation step to confirm every referenced file exists at the chosen ref.
…KILL.md copies (#2274)

b3268fe (#2272) made the write-gate "confirm no existing file" item
tool-agnostic in the JS hook, but the rest of the checklist surface still
names Glob/Grep. On hosts without those tools the agent still hits a dead
tool call on:
- the edit-gate "list importers" item in the hook (scripts/hooks/gateguard-fact-force.js)
- both checklist items in all three SKILL.md copies (en, ja-JP, zh-CN)

Apply the same wording b3268fe introduced — "(search the tree — Glob/Grep,
or find/grep via Bash)" — to those five remaining spots so the whole gate is
consistent. Prose-only; no logic change.

Follow-up to #2272 / b3268fe.
…urity (#2338)

* feat(skills): harden the file upload validation section in django-security

* Update skills/django-security/SKILL.md

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* add missing stuff to second code block

* add import to the top of the code block

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…mpatibility (#2336)

* docs(skills): update Prisma and Zod API patterns for cross-version compatibility

- skills/prisma-patterns: show both adapter-based and direct PrismaClient
  initialization side-by-side; update import paths with conditional notes;
  rewrite version header to be release-agnostic
- skills/backend-patterns: fix ZodError.errors -> ZodError.issues
- skills/coding-standards: fix ZodError.errors -> ZodError.issues
- skills/security-review: fix ZodError.errors -> ZodError.issues

These API differences were discovered during implementation of a
full-stack health assessment project. The updated code samples show
both the new and old API forms so the skill remains useful regardless
of which Prisma or Zod version is installed.

Closes #2335

* fix(skills): revert Prisma client imports to '@prisma/client'

The 'prisma' npm package is the CLI tool, not the runtime client.
Using it as an import source would cause compile-time failures on all
versions. '@prisma/client' remains the correct import source for the
generated PrismaClient and Prisma namespace types.

Found by Greptile during PR review.
…#2347)

* feat(skills): make tdd-workflow test-runner aware (npm/pnpm/yarn/bun)

Add "Step 0: Detect the Test Runner" so the RED/GREEN cycle no longer
hardcodes `npm test`. Distinguishes the package manager from the test
runner (a project can install with Bun yet run Jest/Vitest), adds a runner
command matrix, and warns about `bun test` (native bun:test runner) vs
`bun run test` (runs the package.json script) — a common ESM failure mode.
Adds a Bun native test pattern section and links the bun-runtime skill.

Applied to both the canonical skills/ copy and the .agents/skills/ Codex
subset (manual sync per CONTRIBUTING).

* docs(skills): apply <test>/<coverage> placeholders in tdd-workflow steps

Address review feedback on PR #2347: Step 0 instructs the agent to substitute
the detected runner command, but Steps 3/5/7, Run Coverage Report, Watch Mode,
Pre-Commit, and CI/CD still showed literal `npm test` / `npm run test:coverage`
— so an agent reaching those blocks could run npm test on a pnpm/bun project.
Replace them with the <test> / <test-watch> / <coverage> placeholders from
Step 0. Left untouched: the plan-handoff allowlist example and the Step 8
evidence-table samples (illustrative, not run-this instructions). Applied to
both the canonical and Codex-subset copies.

* docs(skills): make pre-commit lint runner-agnostic via <lint> placeholder

Follow-up to PR #2347 review (CodeRabbit): the pre-commit example still used
`npm run lint`, coupling it to npm after test/coverage were made runner-aware.
Add a `<lint>` column to the Step 0 runner matrix (npm run lint / pnpm lint /
yarn lint / bun run lint) and change the Pre-Commit Hook example to
`<test> && <lint>`. Applied to both the canonical and Codex-subset copies.

* chore: re-trigger CI (flaky windows/node20 npm cell)
…rn-eval (#2348)

skill-create: drop the "Example Output" section (53 lines) — it re-rendered
the same skeleton already defined by the Step 3 output template, just with
filled-in `my-app` values.

learn-eval: drop the "Next Action" column from the 5b verdict table — it
duplicated Step 6's "Verdict-specific confirmation flow". The table now
carries Verdict + Meaning, and a pointer to Step 6 as the single source for
each verdict's action.

No behavior, frontmatter, or design-rationale changes.
…2274 #2338 #2336 #2347 #2348) (#2394)

Regenerate catalog doc counts + command registry after merging the verified
skill/agent batch. Local full suite was green (2924/2924) with these applied.
#2369)

* fix(clv2): align Python _update_registry schema with shell counterpart

The Python `_update_registry` in instinct-cli.py wrote registry entries
without the `id` and `created_at` fields, while the shell counterpart in
detect-project.sh writes both. A projects.json entry could therefore have a
different shape depending on which path (Python CLI or shell hook) last
touched it.

Emit the same field set and order as the shell version: id, name, root,
remote, created_at (preserved from any existing entry), last_seen. Add
regression tests asserting field parity and created_at preservation.

Fixes #2299

* fix(clv2): guard _update_registry against a non-dict registry entry

A malformed projects.json (a non-dict value for the current project id, e.g.
null) would make existing.get("created_at", ...) raise and crash the update,
losing the old code's ability to self-heal a corrupt per-entry value. Normalize
existing to {} when it is not a dict so the entry is healed by the rewrite. Add
a regression test for the malformed-entry path.

* test(clv2): assert the first-write created_at == last_seen contract

The new _update_registry tests only checked both timestamps were truthy. On the
initial write both derive from the same `now`, so created_at must equal
last_seen; assert that explicitly so a later refactor that breaks the contract
is caught. Split the compound assertions into single-expression checks.

* fix(clv2): heal a non-dict top-level registry in _update_registry

A projects.json that is valid JSON but not a mapping (e.g. `[]` or a
string) previously crashed _update_registry on registry.get(), before
the per-entry guard could run, so the corrupt file could not be healed.
Guard the top-level shape right after the load and fall back to {} so the
rewrite repairs the file — matching the per-entry healing already in place.

Resolves the remaining CodeRabbit finding on #2299.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
…ts (#2372)

observe.sh bumps the SIGUSR1 throttle counter in
${PROJECT_DIR}/.observer-signal-counter with an unlocked read-modify-write.
The hook runs on every tool call, so concurrent invocations read the same
value, both increment, and lose a write, signaling the observer at
unpredictable intervals and defeating the #521 throttle.

Serialize the read-modify-write under a lock, and only ever bump the counter
while that lock is held:

- Prefer flock with a bounded -w wait (the OS auto-releases it when the fd
  closes or the process dies, so there is no stale lock and no lost increment);
  on a timeout the tick is skipped rather than bumped unlocked.
- Fall back to an atomic mkdir lock on platforms without flock, with a bounded
  spin. An EXIT trap cleans up on normal completion; INT/TERM traps release the
  lock and exit, so a signal cannot drop the lock and then continue the
  read-modify-write without ownership. If the lock cannot be acquired in the
  budget the tick is skipped rather than raced. No hand-rolled PID stale-reclaim
  (which is racy and can delete a live re-acquirer's lock).
- Guard the counter read against a corrupt (non-integer) file that would abort
  the hook under set -e.

Add tests/hooks/observe-signal-counter-race.test.js: 20 concurrent observe.sh
invocations must not lose increments (exact under flock; at most one dropped on
the best-effort mkdir fallback), the runner rejects on any hook execution
failure or hang, plus content guards for the lock and the corrupt-counter
handling.

Fixes #2296
* fix(clv2): surface SIGALRM timeout drops in observe.sh

The inline-Python observation writers in observe.sh arm a signal.SIGALRM
alarm (8s) so they self-terminate before the async hook's 10s timeout can
orphan them (#2278). The handler _ecc_bail called sys.exit(0) with no
logging, so when the alarm fired the in-flight observation was silently
dropped: nothing was logged, no partial write occurred, and the shell saw
a clean exit. There was no way to detect or count how many observations
were being lost.

Add a single stderr visibility line to both _ecc_bail handlers (the
parse-error fallback path and the main observation-writing path) before
sys.exit(0), using the repo's "[observe]" log prefix. Exit code stays 0:
in a Claude Code hook a non-zero exit signals a block, so changing it
would turn an internal timeout into a user-facing tool block. The warning
goes to stderr (not stdout) because both blocks redirect stdout into the
observations file.

Add tests/hooks/observe-signal-timeout.test.js: a static regression guard
that every _ecc_bail handler logs to stderr before exiting and keeps exit
0, plus a behavioral check that runs the real handler text extracted from
observe.sh and confirms a fired alarm exits 0 and emits the [observe]
warning on stderr only.

Fixes #2300

* test(clv2): exercise both _ecc_bail handlers end-to-end

The behavioral SIGALRM-fire test ran only handlers[0] (the parse-error
fallback path); the main observation-write path (handlers[1]) was covered
only by the static regex guard. The write path is the higher-value one to
verify end-to-end since it carries valid, parseable data that would succeed
given more time, so a silent drop there is the worst case.

Loop the behavioral check over every extracted handler so a regression that
silenced the second handler's stderr write is caught at runtime, not just by
the static guard.

* test(clv2): select timeout handlers by marker, not array index

The behavioral check looped over all extracted _ecc_bail handlers by index.
If an unrelated _ecc_bail were ever added to observe.sh, the loop would
either test the wrong block or be diluted. Filter the handlers to those
carrying the "[observe] SIGALRM timeout" marker so the live SIGALRM check
stays pinned to the two #2300 timeout handlers regardless of array order or
future additions.

* test(clv2): fail fast when python is missing in SIGALRM check

The behavioral test returned early when no python interpreter was found,
which the test harness records as a PASS — so the SIGALRM contract could go
entirely unverified yet still look green. Throw instead, matching the
existing insaits-security-monitor convention of failing when a required
Python runtime is absent, and drop the in-test console.log.
…e dry-run, normalize-url (#2374)

* test(clv2): cover instinct-cli prune, projects ops, promote dry-run, normalize-url

Add pytest coverage for previously-untested functions in
skills/continuous-learning-v2/scripts/instinct-cli.py:

- _normalize_remote_url: scp/https/file forms, credential + .git
  stripping, network lowercasing, case-preserving local paths, idempotence
- _promote_specific dry-run: returns 0 and writes no global file
- projects delete/gc/merge: invalid-id, not-found, dry-run, and force
  paths over registry + storage, asserting destructive ops are gated
- cmd_prune: dry-run keeps files; non-dry-run deletes only expired; quiet

Test-only change; no production code modified.

Fixes #2302

* test(clv2): assert dry-run storage no-op and quiet-mode stderr silence

Address CodeRabbit review on #2374:

- projects gc/merge dry-run tests now also assert on-disk storage is
  untouched (empty1 project dir survives; nothing copied into dest
  personal), closing the gap where a storage-mutating dry-run regression
  would still pass.
- cmd_prune quiet test now asserts stderr is empty too, not just stdout.

* test(clv2): cover merge missing-destination and prune empty-pending branches
…erver-loop (#2386)

analyze_observations moved observations.jsonl into observations.archive/
unconditionally, even when the Claude analysis failed (timeout, non-zero
exit, rate limit). Because the analyzer only reads the live file, a failed
batch was archived and never re-analyzed, silently dropping the instincts
it would have produced.

Return early on a non-zero analysis exit so the archive mv runs only on
success, retaining observations for the next cycle to retry. Resolve the
script's own directory from ${BASH_SOURCE[0]} (SCRIPT_DIR) so sibling
scripts (session-guardian.sh) and relative helpers resolve correctly under
both execution and sourcing, and add a source-guard so observer-loop.sh can
be sourced without starting the loop. Add a regression test covering both
the failure (retain) and success (archive) paths.

Fixes #2370
…C_OBSERVER_MODEL (#2390)

* feat(continuous-learning-v2): make observer model configurable via ECC_OBSERVER_MODEL

The observer hardcoded `--model haiku`. Parameterize as "${ECC_OBSERVER_MODEL:-haiku}": the haiku default is preserved (no behavior change for existing users), but users can opt into a stronger model — e.g. `ECC_OBSERVER_MODEL=opus` — for higher-quality instinct extraction. Useful on subscription plans where model cost isn't the limiting factor.

* fix(continuous-learning-v2): address review — update wiring test + docs

- Update source-inspection test to assert the ${ECC_OBSERVER_MODEL:-haiku} defaulting behavior (was matching the literal `claude --model haiku`, which this PR changed). All 31 tests pass.
- Add guidance to raise ECC_OBSERVER_TIMEOUT_SECONDS for slower models (e.g. opus) so the 120s watchdog doesn't kill analysis mid-run.
- Fix now-stale 'Haiku session' comment -> 'observer session' (model is configurable).
…ve-patterns skill (#2275)

* feat(rules,skills): add React Native / Expo rules pack and react-native-patterns skill

* fix(rules,skills): address review feedback — safeParse nav example, drop deprecated sentry-expo, memoize list renderItem, clarify New Architecture SDK support

* fix(rules,skills): drop deprecated Flipper, surface permission-denied state in location hook
* Add growth-log skill: methodology for writing effective, transferable growth log entries

* Add metadata.origin: ECC frontmatter per repo convention (Greptile feedback)

* Re-sign: apply GPG-verified commit to growth-log branch (rebase artifact, content unchanged)

* docs(growth-log): v1.1.0 — remove personal library structure, generic storage, delivery-gate optional companion
…, assumptions, stale logs, disk space (delivery-gate) (#2378)

* Restore delivery-gate: Stop hook with learning capture enforcement (auto-closed by fork sync, now on clean branch)

* Fix bot findings: log level→INFO (DISK_REMIND dead code), count_edits full transcript (not truncated), memory-dir-absent warning (not silent pass), SKILL.md description accuracy

* Fix CodeRabbit feedback: treat missing memory-dir as all-stale on complex tasks (fail-close instead of fail-open)

* Trigger bot re-review (no logic changes)

* Fix: handle both stdin formats — raw transcript AND JSON with transcript_path (Greptile feedback)

* Add debug log for memory-dir lookup path

* Fix path encoding: replace colon with dash (not strip), matching Claude Code actual encoding on Windows

* Fix SKILL.md: update How It Works for JSON+transcript_path, add English translation to CLAUDE.md block (Greptile feedback)

* Fix: memory-dir absent → warn but don't block (prevents deadlock for new users per Greptile feedback)

* fix: restore daltino-approved voice (thinking quality/收尾铁律) with technical patches

Reverts 'session hygiene' rebranding. Preserves original approved framing
while keeping technical improvements:
- JSON transcript_path parsing documentation
- filesystem mtime staleness check
- 'skip tests for now' rationalization pattern
- disk critically low explicit block condition

* fix: remove stdout JSON echo — Stop hooks write feedback to stderr, not stdout

Previously sys.stdout.write(raw) echoed the raw hook JSON payload to stdout,
which Claude Code displays as the hook's response message. When the hook
blocked (exit 2), Claude saw {"transcript_path":"...","session_id":"..."}
instead of the actual blocking reason from stderr.

This made the gate functionally silent from Claude's perspective — it could
not guide Claude to the corrective action (update growth-log / free disk).

Fix per Greptile feedback: stop echo, let stderr messages reach Claude.

* fix: remove duplicate disk-critical log line

* docs(delivery-gate): v1.1.0 — accurate scope (deterministic checks, not reasoning), warning vs block table, CI/CD analogy, limitations section, self-audit pairing

* fix(delivery-gate): expand rationalization regex coverage (R3/R4) — match "we can fix" and "integration tests" variants

* chore: bump version to 1.1.1 to re-trigger CI checks
* chore(catalog): sync manifests after skill batch (#2275 #2377 #2378 #2381)

Update skill counts (273 -> 277) across catalog docs after the verified skill batch.

* fix(skills): replace emoji with ASCII in growth-log + loop-design-check

check-unicode-safety (pre-push gate) bans emoji in SKILL.md; the merged #2377
and #2381 slipped through run-all.js. Swap U+274C/U+2705 for 'Avoid:'/'Bad:'/'Good:'.
…refix (#2316) (#2409)

* fix(plan-orchestrate): detect ecc@ecc marketplace + emit ecc: agent prefix (#2316)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…veEccRoot() (#2368) (#2410)

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368)

The inline node -e resolver blob was duplicated ~60x across hooks.json,
command docs, and translations. Each copy inlined the full ~700-char
plugin-root search using a spread over nested array literals
(p.join(d,'plugins',...s) over [['ecc'],...]), which breaks Windows hook
execution due to shell quoting (#2368).

Collapse every copy to a 250-char locator that loads the committed
resolve-ecc-root module and delegates to resolveEccRoot() — no spread, no
nested array literals, no escaped double quotes. The real search logic now
lives in one tested module. Also route session-start-bootstrap.js through
resolveEccRoot() instead of its own duplicated reimplementation, and fix
the auto-update.md 'marketplace' (singular) typo along the way.

Guard tests updated: discovery behavior is asserted against resolveEccRoot();
the inline is asserted to delegate and to contain no Windows-fragile
constructs.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(resolve-ecc-root): restore full env-unset discovery in inline resolver

Address Greptile review on #2410: when CLAUDE_PLUGIN_ROOT is unset the
delegating inline could only load the resolver module from ~/.claude,
returning ~/.claude without ever reaching the plugin/cache search. Restore
the old inline's discovery breadth (exact plugin roots + versioned cache)
Windows-safely (no spread, nested arrays, or escaped quotes), then delegate
the authoritative decision to resolveEccRoot(). Add regression tests for
plugin-subdir and versioned-cache bootstrap with env unset.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…issing .gitattributes) (#2437)

* fix: add .gitattributes to force LF line endings for text files

npm run command-registry:check (part of npm test) fails on a fresh clone
on Windows with the common core.autocrlf=true setting: git checks out
docs/COMMAND-REGISTRY.json with CRLF, but generate-command-registry.js
always writes LF, so the strict string comparison in checkRegistry()
never matches. Forcing LF via .gitattributes makes checkouts consistent
across platforms regardless of a contributor's local autocrlf setting.

* fix: normalize CRLF line endings to LF per .gitattributes

pyproject.toml, src/llm/__init__.py, src/llm/prompt/builder.py,
src/llm/providers/claude.py, and tests/test_builder.py had CRLF line
endings committed to the repo, inconsistent with the rest of the
codebase. Renormalized via 'git add --renormalize .' now that
.gitattributes enforces eol=lf.

---------

Co-authored-by: Affaan Mustafa <[email protected]>
…and (#2400)

* feat(workflows): re-land orch-review workflow + add /orch-review command

Re-lands #2363 (reverted by #2393 to unbreak main's lint) and fixes the
root cause so it stays green:

- Restore workflows/orch-review.workflow.js + workflows/README.md.
- eslint.config.js: ignore 'workflows/**/*.workflow.*' and '.claude/workflows/**'
  per the maintainer's note in #2393. Workflow DSL scripts use both top-level
  export (ESM) and top-level return (the runtime wraps them in an async fn),
  which no single eslint sourceType can parse — they must be excluded, not
  lint-fixed. 'npx eslint .' is green with this ignore.
- Add commands/orch-review.md (the /orch-review surface) + regenerate
  docs/COMMAND-REGISTRY.json.

Supersedes #2397 (command-only), which referenced the reverted workflow.

* fix(workflows): address orch-review bot review findings

- Verifier uncertainty no longer demotes blockers (Greptile P1 + CodeRabbit):
  isReal=false only refutes when confidence >= 0.8; low-confidence 'false'
  is treated as uncertain and kept blocking (fail closed).
- Treat the diff (and finding text) as untrusted input in both review and
  verify prompts; ignore embedded directives (prompt-injection hardening).
- Validate changedFiles entries are strings, not just that it is an array.
- Enforce proof for HIGH/CRITICAL in FINDINGS_SCHEMA, not only in the prompt.
- Remove in-place mutation in dimension build + dedup merge (immutable).
- /orch-review: extract & validate a numeric PR id before shelling out to gh.
- Docs: complete the stats example, soften wording, refresh follow-up list.

* style(workflows): apply formatter to orch-review assembly

* fix(plan-orchestrate): detect ecc@ecc marketplace + emit ecc: agent prefix (#2316) (#2409)

* fix(plan-orchestrate): detect ecc@ecc marketplace + emit ecc: agent prefix (#2316)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368) (#2410)

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368)

The inline node -e resolver blob was duplicated ~60x across hooks.json,
command docs, and translations. Each copy inlined the full ~700-char
plugin-root search using a spread over nested array literals
(p.join(d,'plugins',...s) over [['ecc'],...]), which breaks Windows hook
execution due to shell quoting (#2368).

Collapse every copy to a 250-char locator that loads the committed
resolve-ecc-root module and delegates to resolveEccRoot() — no spread, no
nested array literals, no escaped double quotes. The real search logic now
lives in one tested module. Also route session-start-bootstrap.js through
resolveEccRoot() instead of its own duplicated reimplementation, and fix
the auto-update.md 'marketplace' (singular) typo along the way.

Guard tests updated: discovery behavior is asserted against resolveEccRoot();
the inline is asserted to delegate and to contain no Windows-fragile
constructs.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(resolve-ecc-root): restore full env-unset discovery in inline resolver

Address Greptile review on #2410: when CLAUDE_PLUGIN_ROOT is unset the
delegating inline could only load the resolver module from ~/.claude,
returning ~/.claude without ever reaching the plugin/cache search. Restore
the old inline's discovery breadth (exact plugin roots + versioned cache)
Windows-safely (no spread, nested arrays, or escaped quotes), then delegate
the authoritative decision to resolveEccRoot(). Add regression tests for
plugin-subdir and versioned-cache bootstrap with env unset.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: docs/COMMAND-REGISTRY.json check fails on fresh Windows clone (missing .gitattributes) (#2437)

* fix: add .gitattributes to force LF line endings for text files

npm run command-registry:check (part of npm test) fails on a fresh clone
on Windows with the common core.autocrlf=true setting: git checks out
docs/COMMAND-REGISTRY.json with CRLF, but generate-command-registry.js
always writes LF, so the strict string comparison in checkRegistry()
never matches. Forcing LF via .gitattributes makes checkouts consistent
across platforms regardless of a contributor's local autocrlf setting.

* fix: normalize CRLF line endings to LF per .gitattributes

pyproject.toml, src/llm/__init__.py, src/llm/prompt/builder.py,
src/llm/providers/claude.py, and tests/test_builder.py had CRLF line
endings committed to the repo, inconsistent with the rest of the
codebase. Renormalized via 'git add --renormalize .' now that
.gitattributes enforces eol=lf.

---------

Co-authored-by: Affaan Mustafa <[email protected]>

* chore(catalog): sync command counts (92->93) + register orch-review in agent.yaml surface

---------

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: affaan <[email protected]>
Co-authored-by: Boube <[email protected]>
Co-authored-by: Affaan Mustafa <[email protected]>
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (126 files found, 80 file limit)

Bypass the limit by tagging @greptile-apps to review.

@ecc-tools

ecc-tools Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@affaan-m
affaan-m merged commit 7a46a7b into main Jul 4, 2026
42 of 43 checks passed
@affaan-m
affaan-m deleted the docs/ecc-pro-security-roadmap branch July 4, 2026 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.