Skip to content

Conversation

@ksamaschke
Copy link
Collaborator

  • hook: workflow-enforcement with configurable Task→Plan→Review→Execute→Review→Document sequence
  • config: new enforcement.workflow block + workflow-reviewed sample preset
  • fix: main_scope_has_agent_privileges no longer disables ~/.claude protection, but still bypasses project-boundary blocks
  • docs/changelog/version bumped to 8.20.91

* fix: allow markdown docs in any path segment

* fix: use configured allowlist for markdown in any path segment

* fix: allow markdown by path segment and clean path normalization

* fix: guard pm markdown allowlist and inherit parent-path rules

* fix: enforce parent-path rules before markdown allow segments
* fix: enforce parent-path rule before markdown segment allowlist

* test: cover parent-path markdown allow when setting enabled

* fix: run markdown segment allowlist after parent-path guard

* feat: add configurable auto commit review reminder
* fix: ensure markdown segment allowlist honors parent gate

* docs: add sample ICC configs for main/sub-agent and strict/relaxed

* feat: parametrized config deployment and sample icc configs

* chore: snapshot current config and tighten main-scope sample agents block

* fix: preserve existing icc.config.json unless override provided

* chore: rename local config backup and document it

* chore: clarify/preserve existing icc.config on ansible reinstall
* fix: apply infra policy checks to full command incl. ssh wrapper

* fix: tighten docs fast-path (no heredoc/chaining; only under project docs)

* docs: fix duplicate Added header in 8.20.88 changelog

* fix: docs fast-path requires path under cwd with segment boundary
* fix: doc fast-path only blocks unquoted substitution

* fix: aggressive ALL-CAPS detection handles mixed separators

* fix: treat double-quoted substitution as unsafe doc fast-path

* fix: respect escaped substitutions in doc fast-path
* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* fix: support nested markdown allowlist segments (#266)

* fix: allow nested allowlist paths for markdown

* chore: dedupe markdown allowlist sequences

* feat: linux main-scope friendly config + guardrail defaults (#272)

* feat: add main-scope dev preset and config-driven bash allowlist

* fix: scope config main-scope bash allowlist to main-role

* fix: doc fast-path & constraint display (#274)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* chore: sync dev with main (#275)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* feat: main scope agent privilege flag (#278)

* feat: allow main scope to inherit agent privileges

* docs: clarify main scope agent flag impact

* Merge dev into main (v8.20.89) (#273) (#280)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: allow markdown when any path segment is docs (#259)

* fix: allow markdown docs in any path segment

* fix: use configured allowlist for markdown in any path segment

* fix: allow markdown by path segment and clean path normalization

* fix: guard pm markdown allowlist and inherit parent-path rules

* fix: enforce parent-path rules before markdown allow segments

* fix: enforce parent-path before markdown segment allowlist (#261)

* fix: enforce parent-path rule before markdown segment allowlist

* test: cover parent-path markdown allow when setting enabled

* fix: run markdown segment allowlist after parent-path guard

* feat: add configurable auto commit review reminder

* fix: markdown segment allowlist respects parent-path gate (#262)

* fix: ensure markdown segment allowlist honors parent gate

* docs: add sample ICC configs for main/sub-agent and strict/relaxed

* feat: parametrized config deployment and sample icc configs

* chore: snapshot current config and tighten main-scope sample agents block

* fix: preserve existing icc.config.json unless override provided

* chore: rename local config backup and document it

* chore: clarify/preserve existing icc.config on ansible reinstall

* fix: enforce infra policy on full command including ssh wrapper (#264)

* fix: apply infra policy checks to full command incl. ssh wrapper

* fix: tighten docs fast-path (no heredoc/chaining; only under project docs)

* docs: fix duplicate Added header in 8.20.88 changelog

* fix: docs fast-path requires path under cwd with segment boundary

* fix: make doc fast-path allow literal markdown code (#269)

* fix: doc fast-path only blocks unquoted substitution

* fix: aggressive ALL-CAPS detection handles mixed separators

* fix: treat double-quoted substitution as unsafe doc fast-path

* fix: respect escaped substitutions in doc fast-path

* fix: support nested markdown allowlist segments (#266)

* fix: allow nested allowlist paths for markdown

* chore: dedupe markdown allowlist sequences

* feat: linux main-scope friendly config + guardrail defaults (#272)

* feat: add main-scope dev preset and config-driven bash allowlist

* fix: scope config main-scope bash allowlist to main-role

* fix: doc fast-path & constraint display (#274)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* chore: sync dev with main (#275)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* Merge dev into main (v8.20.89) (#273) (#281)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: allow markdown when any path segment is docs (#259)

* fix: allow markdown docs in any path segment

* fix: use configured allowlist for markdown in any path segment

* fix: allow markdown by path segment and clean path normalization

* fix: guard pm markdown allowlist and inherit parent-path rules

* fix: enforce parent-path rules before markdown allow segments

* fix: enforce parent-path before markdown segment allowlist (#261)

* fix: enforce parent-path rule before markdown segment allowlist

* test: cover parent-path markdown allow when setting enabled

* fix: run markdown segment allowlist after parent-path guard

* feat: add configurable auto commit review reminder

* fix: markdown segment allowlist respects parent-path gate (#262)

* fix: ensure markdown segment allowlist honors parent gate

* docs: add sample ICC configs for main/sub-agent and strict/relaxed

* feat: parametrized config deployment and sample icc configs

* chore: snapshot current config and tighten main-scope sample agents block

* fix: preserve existing icc.config.json unless override provided

* chore: rename local config backup and document it

* chore: clarify/preserve existing icc.config on ansible reinstall

* fix: enforce infra policy on full command including ssh wrapper (#264)

* fix: apply infra policy checks to full command incl. ssh wrapper

* fix: tighten docs fast-path (no heredoc/chaining; only under project docs)

* docs: fix duplicate Added header in 8.20.88 changelog

* fix: docs fast-path requires path under cwd with segment boundary

* fix: make doc fast-path allow literal markdown code (#269)

* fix: doc fast-path only blocks unquoted substitution

* fix: aggressive ALL-CAPS detection handles mixed separators

* fix: treat double-quoted substitution as unsafe doc fast-path

* fix: respect escaped substitutions in doc fast-path

* fix: support nested markdown allowlist segments (#266)

* fix: allow nested allowlist paths for markdown

* chore: dedupe markdown allowlist sequences

* feat: linux main-scope friendly config + guardrail defaults (#272)

* feat: add main-scope dev preset and config-driven bash allowlist

* fix: scope config main-scope bash allowlist to main-role

* fix: doc fast-path & constraint display (#274)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)

* chore: sync dev with main (#275)

* Release 8.20.89 (dev -> main) (#252)

* feat: surface MCP availability hints and gate MCP tools via config

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* Release 8.20.89 (dev -> main) (#253)

* feat: surface MCP availability hints and gate MCP tools via config (#246)

* fix: allow docs/documentation writes in main scope allowlist (#247)

* chore: add config presets and docs allowlist coverage (#248)

* docs: streamline README and docs index (#249)

* fix: allow docs heredoc writes without infra blocking (#250)

* feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251)

* fix: tighten docs heredoc allow to prevent infra bypass (#254)

* fix: allow nested docs paths and harden docs write allowlist (#255)
Copilot AI review requested due to automatic review settings November 19, 2025 21:09
@ksamaschke
Copy link
Collaborator Author

@codex review

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces workflow enforcement (v8.20.91) with a configurable Task→Plan→Review→Execute→Review→Document sequence, fixes the main_scope_has_agent_privileges behavior to bypass project boundaries without disabling ~/.claude protection, and includes extensive test coverage and sample configurations.

Key Changes:

  • New workflow-enforcement hook with stateful step validation
  • Centralized agent context detection via lib/marker-detection.js
  • ALL-CAPS filename detection extracted to reusable lib/allcaps-detection.js module
  • Documentation write fast-path for infra protection hook

Reviewed Changes

Copilot reviewed 41 out of 41 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/hooks/workflow-enforcement.js New hook enforcing configurable workflow steps with session-based state tracking
src/hooks/lib/marker-detection.js Centralized agent context detection supporting main_scope_has_agent_privileges flag
src/hooks/lib/allcaps-detection.js Extracted ALL-CAPS filename detection logic for reuse across hooks
src/hooks/lib/command-validation.js Role-based command allowlist with configurable main-scope bash commands
src/hooks/agent-infrastructure-protection.js Documentation write fast-path bypassing infra keyword checks
src/hooks/pm-constraints-enforcement.js Refactored to use centralized marker detection and segment-based path validation
src/hooks/summary-file-enforcement.js Uses shared allcaps-detection and marker-detection modules
src/hooks/main-scope-enforcement.js Integrated allcaps-detection and expanded docs directory defaults
src/hooks/project-scope-enforcement.js Conditional project boundary enforcement based on main_scope_has_agent_privileges
src/hooks/context-injection.js MCP hints and mandatory constraint block format instructions
icc.config.default.json Added workflow enforcement config block and main_scope_has_agent_privileges flag
tests/hooks/integration/test-workflow-enforcement.js Integration test validating workflow state machine behavior
tests/hooks/unit/test-allcaps-detection.js Unit tests for aggressive ALL-CAPS detection
tests/hooks/unit/test-marker-detection.js Test for main_scope_has_agent_privileges override
tests/hooks/unit/test-pm-markdown-allowlist.js Tests for markdown path allowlist with parent path handling
sample-configs/* Six sample configurations covering relaxed, strict, workflow, and dev presets
Makefile, install.ps1, ansible/* CONFIG_FILE parameter support for preset installation
VERSION, CHANGELOG.md, README.md Version bump to 8.20.91 with comprehensive changelog entries

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 197 to 207
"heredoc_allowed_commands": [
"git",
"gh",
"glab",
"hub"
],
"auto_commit_review": {
"enabled": false,
"command": "@codex review"
},
"infrastructure_protection": {
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

JSON structure error: "heredoc_allowed_commands" (line 197), "auto_commit_review" (line 203), and "infrastructure_protection" (line 207) are indented at the same level as the "enforcement" object, but they should be properties inside the "enforcement" object. These properties need to be indented one level deeper to be nested correctly within the enforcement configuration block.

Copilot uses AI. Check for mistakes.
// Process monitoring
'ps', 'top', 'jobs', 'bg', 'fg'
];
, ...configAllowed];
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Syntax error: line 76 has a comma followed by spread operator ...configAllowed at the end of the array literal. This should be just ...configAllowed without the leading comma, or the array should be closed first and then concatenated. The correct syntax would be ].concat(configAllowed) or moving the spread inside: 'ps', 'top', 'jobs', 'bg', 'fg', ...configAllowed.

Copilot uses AI. Check for mistakes.
// Shared libraries
const { initializeHook } = require('./lib/logging');
const { extractToolInfo, generateProjectHash, allowOperation, blockResponse, sendResponse } = require('./lib/hook-helpers');
const { extractToolInfo, allowOperation, blockResponse, sendResponse } = require('./lib/hook-helpers');
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Unused variable blockResponse.

Copilot uses AI. Check for mistakes.
const { initializeHook } = require('./lib/logging');
const { isAllowedCoordinationCommand } = require('./lib/command-validation');
const { getProjectRoot, generateProjectHash } = require('./lib/hook-helpers');
const { getProjectRoot } = require('./lib/hook-helpers');
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Unused variable getProjectRoot.

Suggested change
const { getProjectRoot } = require('./lib/hook-helpers');
// Removed unused getProjectRoot import

Copilot uses AI. Check for mistakes.
#!/usr/bin/env node
const assert = require('assert');
const path = require('path');
const os = require('os');
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Unused variable os.

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 100 to 101
const mainScopeAgent = getSetting('enforcement.main_scope_has_agent_privileges', false) === true;

Choose a reason for hiding this comment

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

P2 Badge Respect ICC_MAIN_SCOPE_AGENT override in project boundary check

Project boundary enforcement only consults enforcement.main_scope_has_agent_privileges from config (mainScopeAgent), ignoring the ICC_MAIN_SCOPE_AGENT=true override that marker-detection and the changelog advertise for treating the main scope like an agent. With the env var set, other hooks will skip PM limits, but project-scope-enforcement will still block writes outside the project root because mainScopeAgent remains false. This makes the new agent-privileges override inconsistent: e.g., launching a session with ICC_MAIN_SCOPE_AGENT=true and running Write to /tmp/docs/note.md is still denied by the boundary check. Consider incorporating the env override (as marker-detection does) so the bypass works when enabled intentionally.

Useful? React with 👍 / 👎.

@ksamaschke
Copy link
Collaborator Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. You're on a roll.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings November 20, 2025 14:43
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -1 +1 @@
8.20.90
8.20.91
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Version mismatch: root VERSION file shows 8.20.91 but src/VERSION shows 8.20.92. These should be synchronized. Based on the PR title mentioning v8.20.91, update src/VERSION to 8.20.91 to match.

Copilot uses AI. Check for mistakes.
@@ -1 +1 @@
8.20.90
8.20.92
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Version mismatch: src/VERSION shows 8.20.92 but root VERSION file shows 8.20.91. These should be synchronized. Based on the PR title mentioning v8.20.91, this should be 8.20.91 to match the root VERSION file.

Suggested change
8.20.92
8.20.91

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +104
allowOperation(log, true);
}

if (!hookInput || !hookInput.session_id) {
allowOperation(log, true);
}

const toolName = normalizeToolName(hookInput.tool_name || hookInput.tool);
if (!toolName) {
allowOperation(log, true);
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Missing return statements in early exit conditions (lines 95, 99, 104). The allowOperation function calls process.exit(), so execution will stop, but the missing return makes the control flow unclear. Add return before each allowOperation() call for code clarity and to prevent linter warnings.

Suggested change
allowOperation(log, true);
}
if (!hookInput || !hookInput.session_id) {
allowOperation(log, true);
}
const toolName = normalizeToolName(hookInput.tool_name || hookInput.tool);
if (!toolName) {
allowOperation(log, true);
return allowOperation(log, true);
}
if (!hookInput || !hookInput.session_id) {
return allowOperation(log, true);
}
const toolName = normalizeToolName(hookInput.tool_name || hookInput.tool);
if (!toolName) {
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.

if (!state.active) {
if (!firstStep || !toolMatches(firstStep, toolName)) {
blockOperation(`Workflow enforcement active. Start with the ${firstStep?.name || 'first'} step before running ${toolName}.`, log);
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Missing return statement before blockOperation() call. Although blockOperation calls process.exit(), the missing return makes control flow unclear. Add return for consistency with other hooks.

Suggested change
blockOperation(`Workflow enforcement active. Start with the ${firstStep?.name || 'first'} step before running ${toolName}.`, log);
return blockOperation(`Workflow enforcement active. Start with the ${firstStep?.name || 'first'} step before running ${toolName}.`, log);

Copilot uses AI. Check for mistakes.
state.nextIndex = 1;
saveState(state);
}
allowOperation(log, true);
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Missing return statement before allowOperation() call. This is after saving state and should explicitly return to indicate the end of this execution path.

Suggested change
allowOperation(log, true);
allowOperation(log, true);
return;

Copilot uses AI. Check for mistakes.
const expectedStep = settings.steps[state.nextIndex] || null;

if (!expectedStep || !toolMatches(expectedStep, toolName)) {
blockOperation(`Workflow enforcement active. Expected ${expectedStep?.name || 'next'} before running ${toolName}.`, log);
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Missing return statement before blockOperation() call. Add return for consistency and clarity.

Copilot uses AI. Check for mistakes.
saveState(state);
}

allowOperation(log, true);
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Missing return statement before final allowOperation() call. Add return for consistency.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [8.20.92] - 2025-11-19
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

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

Version mismatch in CHANGELOG: Entry shows 8.20.92 but the PR title and root VERSION file indicate this is release 8.20.91. The 8.20.92 entry should either be renamed to 8.20.91 or moved to a separate PR if these are intended to be different releases.

Copilot uses AI. Check for mistakes.
@ksamaschke
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -1 +1 @@
8.20.90
8.20.91

Choose a reason for hiding this comment

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

P2 Badge Align root and source version numbers

The release metadata is inconsistent: CHANGELOG.md and src/VERSION both advertise 8.20.92, but the root VERSION file remains at 8.20.91, so any tooling that reads VERSION (many packaging/CI scripts do) will report the older version while the code and changelog indicate the newer one. Please bump the root version to match so the release number is unambiguous.

Useful? React with 👍 / 👎.

Copilot AI review requested due to automatic review settings November 22, 2025 10:21
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if (!isQuoted) {
// Unquoted heredoc bodies perform substitution; ensure body is clean
const body = trimmed.replace(/^.*?\n/s, '');
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

The heredoc body extraction logic is incorrect. The regex /^.*?\n/s with the s flag makes . match newlines, causing the *? to match everything up to the last newline before the terminator, effectively removing the entire body except the last line.

The correct approach is to remove only the first line (without the s flag): trimmed.replace(/^.*?\n/, '')

For example, with input:

cat <<EOF > file
line1
line2
EOF

Current code extracts: EOF (just the terminator line)
Should extract: line1\nline2\nEOF

Suggested change
const body = trimmed.replace(/^.*?\n/s, '');
const body = trimmed.replace(/^.*?\n/, '');

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +85

const planFirst = runHook(projectDir, 'Plan', sessionId);
assert.strictEqual(planFirst.code, 2, 'Plan before Task should be blocked');

const allowedSequence = ['Task', 'Plan', 'Review', 'Execute', 'Document'];
allowedSequence.forEach((tool, index) => {
const result = runHook(projectDir, tool, sessionId);
assert.strictEqual(result.code, 0, `Step ${index + 1} (${tool}) should be allowed`);
});

const restart = runHook(projectDir, 'Task', sessionId);
assert.strictEqual(restart.code, 0, 'Workflow should reset after Document');

const outOfOrder = runHook(projectDir, 'Execute', sessionId);
assert.strictEqual(outOfOrder.code, 2, 'Execute before Plan should be blocked in new cycle');

console.log('✅ Workflow enforcement integration tests passed');
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

[nitpick] Missing cleanup of temporary test directory. The test creates a temporary directory in createTestProject() but never cleans it up after the tests complete. This can lead to accumulation of test directories in the system's temp folder over time.

Consider adding cleanup logic at the end of the test suite:

try {
  // ... existing test code ...
} finally {
  fs.rmSync(projectDir, { recursive: true, force: true });
}
Suggested change
const planFirst = runHook(projectDir, 'Plan', sessionId);
assert.strictEqual(planFirst.code, 2, 'Plan before Task should be blocked');
const allowedSequence = ['Task', 'Plan', 'Review', 'Execute', 'Document'];
allowedSequence.forEach((tool, index) => {
const result = runHook(projectDir, tool, sessionId);
assert.strictEqual(result.code, 0, `Step ${index + 1} (${tool}) should be allowed`);
});
const restart = runHook(projectDir, 'Task', sessionId);
assert.strictEqual(restart.code, 0, 'Workflow should reset after Document');
const outOfOrder = runHook(projectDir, 'Execute', sessionId);
assert.strictEqual(outOfOrder.code, 2, 'Execute before Plan should be blocked in new cycle');
console.log('✅ Workflow enforcement integration tests passed');
try {
const planFirst = runHook(projectDir, 'Plan', sessionId);
assert.strictEqual(planFirst.code, 2, 'Plan before Task should be blocked');
const allowedSequence = ['Task', 'Plan', 'Review', 'Execute', 'Document'];
allowedSequence.forEach((tool, index) => {
const result = runHook(projectDir, tool, sessionId);
assert.strictEqual(result.code, 0, `Step ${index + 1} (${tool}) should be allowed`);
});
const restart = runHook(projectDir, 'Task', sessionId);
assert.strictEqual(restart.code, 0, 'Workflow should reset after Document');
const outOfOrder = runHook(projectDir, 'Execute', sessionId);
assert.strictEqual(outOfOrder.code, 2, 'Execute before Plan should be blocked in new cycle');
console.log('✅ Workflow enforcement integration tests passed');
} finally {
fs.rmSync(projectDir, { recursive: true, force: true });
}

Copilot uses AI. Check for mistakes.
Comment on lines +969 to +987
// Docs fast-path: if markdown is already allowed via docs/ allowlist (including parent-path fast path), skip blacklist
let markdownAllowedFastPath = false;
if (filePath && filePath.endsWith('.md')) {
const markdownValidation = validateMarkdownOutsideAllowlist(filePath, projectRoot, false);
const outsideProject = path.relative(projectRoot, filePath).startsWith('..');
const allowlistDirs = [
getSetting('paths.story_path', 'stories'),
getSetting('paths.bug_path', 'bugs'),
getSetting('paths.memory_path', 'memory'),
getSetting('paths.docs_path', 'docs'),
'agenttasks',
getSetting('paths.summaries_path', 'summaries')
];
const pathParts = path.normalize(filePath).split(path.sep);
const containsAllowlistedSegment = allowlistDirs.some((dir) => pathParts.includes(dir));
const forceAllow = ALLOW_PARENT_ALLOWLIST_PATHS && outsideProject && containsAllowlistedSegment;

markdownAllowedFastPath = markdownValidation.allowed || forceAllow;
}
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Duplicated logic: The allowlist directory definitions and the parent path validation logic (lines 974-984) are nearly identical to lines 1119-1128. This creates a maintenance burden where changes need to be made in two places.

Consider extracting this logic into a helper function, e.g., checkMarkdownParentPathAllowlist(filePath, projectRoot) that can be called from both locations.

Copilot uses AI. Check for mistakes.
const { log, hookInput } = initializeHook('workflow-enforcement');

if (!settings.enabled || settings.steps.length === 0) {
allowOperation(log, true);
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Missing return statement before allowOperation. When workflow is disabled or has no steps, the function should return after allowing the operation, but it continues to execute the rest of the function instead. This will cause the workflow enforcement logic to run even when it's disabled.

Add return before allowOperation(log, true); on line 95.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.
}

if (!hookInput || !hookInput.session_id) {
allowOperation(log, true);
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Missing return statement before allowOperation. When hookInput or session_id is missing, the function should return after allowing the operation, but it continues to execute the rest of the function instead.

Add return before allowOperation(log, true); on line 99.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.

const toolName = normalizeToolName(hookInput.tool_name || hookInput.tool);
if (!toolName) {
allowOperation(log, true);
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Missing return statement before allowOperation. When tool name is missing, the function should return after allowing the operation, but it continues to execute the rest of the function instead.

Add return before allowOperation(log, true); on line 104.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.
state.nextIndex = 1;
saveState(state);
}
allowOperation(log, true);
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Missing return statement before allowOperation. After allowing the first step in the workflow, the function should return, but it continues to execute the subsequent workflow state checks instead, which will incorrectly try to match against expectedStep (which would be the second step).

Add return before allowOperation(log, true); on line 120.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.
saveState(state);
}

allowOperation(log, true);
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

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

Missing return statement before final allowOperation. After successfully completing a workflow step, the function should return, but instead execution continues and could potentially reach the catch block or other code paths.

Add return before allowOperation(log, true); on line 137.

Suggested change
allowOperation(log, true);
return allowOperation(log, true);

Copilot uses AI. Check for mistakes.
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.

2 participants