Skip to content

feat: sentinel-based disable guards and session-start-context hook#220

Merged
dean0x merged 15 commits into
mainfrom
feature/triage-layer-ci-gate
May 16, 2026
Merged

feat: sentinel-based disable guards and session-start-context hook#220
dean0x merged 15 commits into
mainfrom
feature/triage-layer-ci-gate

Conversation

@dean0x
Copy link
Copy Markdown
Owner

@dean0x dean0x commented May 14, 2026

Summary

  • Add runtime sentinel files (.memory/.working-memory-disabled, .memory/.learning-disabled) so hooks respect enable/disable state at the shell level, independently of whether hooks are registered in settings.json
  • Extract cross-feature context injection (decisions TL;DR, learned behaviors, manifest reconciliation) from session-start-memory into a new always-on session-start-context hook — memory can be disabled without losing context injection
  • Fix a gap where the decisions usage scanner in stop-update-memory ran even when decisions were disabled

Changes

New hook (scripts/hooks/session-start-context):

  • Always-on SessionStart hook, never removed by devflow memory --disable
  • Sections 1.4 (manifest reconciliation), 1.5 (decisions TL;DR), 1.75 (learned behaviors) extracted from session-start-memory
  • Internally gated: decisions section checks decisions/.disabled; learning sections check .learning-disabled

Sentinel guards added to hooks:

  • prompt-capture-memory, stop-update-memory, background-memory-update, pre-compact-memory: exit on .working-memory-disabled
  • session-end-learning: exit on .learning-disabled
  • decisions-usage-scan.cjs: exit on decisions/.disabled
  • stop-update-memory: decisions scanner invocation now gated on decisions sentinel

CLI wiring (init.ts, memory.ts, learn.ts, uninstall.ts):

  • devflow init: registers session-start-context (always-on, remove-then-add for idempotency); manages both sentinels based on feature state
  • devflow memory --enable: removes .working-memory-disabled sentinel; --disable: creates it; --status: warns if sentinel present
  • devflow learn --enable: removes .learning-disabled sentinel; --disable: creates it; --status: warns if sentinel present
  • devflow uninstall: removes session-start-context hook from settings.json

Tests: 35 new sentinel tests in tests/sentinel.test.ts covering all sentinel guard paths, scanner gating, context hook registration, CLI sentinel management, and shell syntax. Memory test suite updated: session-start-memory tests adjusted to reflect extraction; new session-start-context integration test block added.

Breaking Changes

None. The sentinel files are additive. Existing installs with hooks registered continue to work — sentinels only exist if explicitly created by --disable.

Reviewer Focus Areas

  • scripts/hooks/session-start-context: verify sections match what was in session-start-memory exactly (1.4, 1.5, 1.75)
  • src/cli/commands/init.ts: addContextHook/removeContextHook/hasContextHook follow the same pattern as memory/learning hook utilities
  • Early-exit logic in memory.ts and learn.ts enable/disable: verify both "already enabled" and "not yet enabled" paths still work correctly after the early return refactoring
  • tests/sentinel.test.ts: 35 tests — confirm coverage is complete for all guard paths

…gate

Ambient mode over-classifies simple tasks as ORCHESTRATED, wasting tokens
on full agent pipelines for work that only needs GUIDED treatment. This
separates intent classification from depth classification: the router
determines WHAT kind of work; a new per-intent triage skill determines
HOW BIG the work is, using actual context (file counts, issue content,
commit count). Default-to-GUIDED bias inverts the previous
default-to-ORCHESTRATED behavior.

Additionally, implement and resolve workflows now verify CI passes after
code changes via a new check-ci-status Git agent operation with polling
and fix loop.

Change A — Triage Layer:
- 7 new triage skills (implement, debug, explore, plan, review, research, release)
- Router dispatch table simplified to intent-only (single column)
- Classification rules: depth criteria removed, QUICK criteria preserved
- Preamble: intent-only classification trigger
- Tests updated for new router format and triage skill chain

Change B — CI Status Gate:
- New check-ci-status operation in Git agent
- Phase 7 CI gate in implement:orch (phases renumbered 7→8, 8→9)
- Phase 7 CI gate in resolve:orch, resolve.md, resolve-teams.md
- Polls pending CI (max 10 min), attempts fixes (max 2), graceful fallback
@dean0x
Copy link
Copy Markdown
Owner Author

dean0x commented May 14, 2026

PR Review: Blocking Issues Summary

Phase 3 Synthesis — Findings from 9 Reviewers (≥80% confidence)

Thank you for this well-architected triage layer. The reviewers identified 17 findings, with 13 at ≥80% confidence. Here's the consolidated list:

BLOCKING ISSUES (Must fix before merge)

1. Consistency: 4 Stale Phase Cross-References (95% confidence)
The CI Status Gate insertion shifted phases (now 7→8, 8→9). These cross-references are stale and will cause incorrect phase numbering in agent execution:

  • resolve-teams.md:231 — Phase 5 says "Phase 8" → should be "Phase 9"
  • resolve-teams.md:383 — Output Artifact says "Phase 8" → should be "Phase 9"
  • resolve.md:184 — Phase 5 comment says "Phase 8" → should be "Phase 9"
  • implement:orch/SKILL.md:223 — Phase 9 says "Phase 7" → should be "Phase 8"

2. Regression: 2 Stale Phase References in pipeline:orch (92% confidence)

  • pipeline:orch/SKILL.md:35 — Says implement:orch has "Phases 1-7" → should be "Phases 1-9"
  • pipeline:orch/SKILL.md:35 & 39 — "Phase 7" cleanup reference → should be "Phase 8"
  • pipeline:orch/SKILL.md:78 — Says resolve:orch has "Phases 1-7" → should be "Phases 1-8"

3. Architecture: 2 Blocking Issues with CI Status Gate (82-85% confidence)

  • shared/skills/resolve:orch/SKILL.md:126CI fix path bypasses quality gates: Phase 7 spawns Coder to fix CI failures with no scope constraints and pushes directly without Validator. Coder could disable tests or weaken configs. Add constraints: (1) restrict to files directly related to failing check, (2) run Validator before pushing, (3) prohibit disabling tests.
  • plugins/devflow-resolve/commands/resolve.md:260CI Status Gate lacks bounded retry spec: Coder spawned for CI fixes has no scope constraints on what files can be modified. This violates reliability principle PF-005 (all loops must have explicit bounds). Specify that Coder should only modify files directly related to failing checks.

4. Reliability: 2 CI Polling Issues (85-92% confidence)

  • shared/skills/implement:orch/SKILL.md:161CI polling lacks total wall-clock timeout: Poll loop is max 10 iterations (600s), but if status transitions PENDING→FAILING after polling, Coder fix-and-recheck could enter another PENDING cycle with unclear budget. Specify total CI gate wall-clock budget.
  • shared/agents/git.md:292CI check classification allows FAILING to mask PENDING: If one check failed and another still pending, status is FAILING and Coder is spawned speculatively. Handle mixed FAILURE+PENDING explicitly.

5. Security: 1 Shell Injection Issue (82% confidence)

  • shared/skills/implement:triage/SKILL.md:23Unvalidated issue number in gh command: Triage skill extracts #NNN from user prompt and runs gh issue view NNN without validating NNN is digits-only. Model extraction could produce shell metacharacters. Add explicit validation: extract digits via ^[0-9]+$ and skip if validation fails.

6. Complexity: 1 DRY Violation (88% confidence)

  • CI Status Gate duplicated across 4 files: The 5-step polling/fix logic is duplicated verbatim in:

    • shared/skills/implement:orch/SKILL.md:153-162
    • shared/skills/resolve:orch/SKILL.md:113-126
    • plugins/devflow-resolve/commands/resolve.md:201-214
    • plugins/devflow-resolve/commands/resolve-teams.md:248-261

    Any future change requires updating all 4 in lockstep. Add <!-- SYNC: CI Status Gate logic — also in [other 3 locations] --> comments to each location to make drift detectable.

7. TypeScript: 1 Dead Code Issue (82% confidence)

  • tests/integration/helpers.ts:5Dead CHAT variant in CLASSIFICATION_PATTERN: Pattern includes CHAT in alternation but CHAT intent is QUICK-only and never emits Devflow: CHAT. marker. Remove CHAT from pattern: (EXPLORE|PLAN|IMPLEMENT|DEBUG|REVIEW|RESOLVE|PIPELINE|RESEARCH|RELEASE).

8. Testing: 1 Missing Negative Test (85% confidence)

  • tests/ambient.test.ts:414-417Missing negative test for old INTENT/DEPTH format rejection: Test extractDepth only tests new Scope: format. Add negative assertion confirming old INTENT/DEPTH format (e.g., Devflow: IMPLEMENT/GUIDED) is not parsed. Important for clean-break validation (ADR-001).

SHOULD-FIX ISSUES (Recommended but not blocking)

1. Regression: Stale Format References in Adjacent Skills (85-90% confidence)

  • shared/skills/test-driven-development/SKILL.md:154-201 — Uses old INTENT/DEPTH format throughout "Ambient Mode Integration" section. Update to match new classification output format.
  • shared/skills/pipeline:orch/SKILL.md:27 — Cost communication template says PIPELINE/ORCHESTRATED but router now emits {INTENT} without /DEPTH. Update example to new format.

LOWER CONFIDENCE (60-79%)

Four additional findings below 80% confidence are documented in individual review reports:

  • Security (65%): Orchestration hint keywords could be weaponized in PR descriptions
  • Security (60%): CI poll loop has no jitter or backoff
  • Performance (80%): gh issue view adds 200-500ms latency on every issue-referencing prompt (acceptable trade-off)
  • Reliability (72-65%): Triage skill error handling and edge cases

Summary

Category Count Severity
Blocking 8 Must fix
Should-Fix 2 Recommended
Lower Confidence 4 FYI
Total 14

Recommendation: CHANGES_REQUESTED — The triage layer is architecturally sound, but the blocking issues (stale phase references, CI gate scope constraints, DRY violations) must be resolved before merge.


Generated by: Devflow Code Review (9 reviewers, synthesized 2026-05-14)
PR: #220 (feature/triage-layer-ci-gate → main)

See individual review reports in .docs/reviews/feature-triage-layer-ci-gate/2026-05-14_1424/ for detailed analysis.

Dean Sharon added 3 commits May 14, 2026 17:50
…EPTH format CHAT is always QUICK and never emits the 'Devflow: INTENT.' marker, so it was a dead branch in CLASSIFICATION_PATTERN. Remove it for clarity. Add negative test asserting the old INTENT/DEPTH slash format is rejected — applies ADR-001 (clean break philosophy: explicitly verify old format is not matched). Co-Authored-By: Claude <noreply@anthropic.com>
…hase 7 (CI Status Gate) was inserted into implement:orch and resolve:orch, shifting downstream phases by one. This commit corrects all stale phase references across resolve.md, resolve-teams.md, implement:orch, pipeline:orch, plan:orch, and test-driven-development to reflect the updated numbering. Also updates the Integration with Ambient Mode section in test-driven-development from the old INTENT/DEPTH format to the new parenthetical INTENT (DEPTH) format, and replaces the stale PIPELINE/ORCHESTRATED cost label in pipeline:orch with the canonical PIPELINE label. Co-Authored-By: Claude <noreply@anthropic.com>
…CI status classification rules in the check-ci-status operation to be more explicit about priority order: PENDING state takes precedence over FAILURE, which takes precedence over SUCCESS. This matches the actual implementation behavior and makes the intent clearer. Co-Authored-By: Claude <noreply@anthropic.com>
@dean0x
Copy link
Copy Markdown
Owner Author

dean0x commented May 14, 2026

Review Comments - helpers.ts

Line 5: CHAT removal from CLASSIFICATION_PATTERN

Good catch: CHAT removal is correct. CHAT intents are always QUICK (never emit the 'Devflow: INTENT.' marker per classification-rules.md line 20), making CHAT a dead branch in this regex. This applies ADR-001 (clean break -- dead code removed without backward-compat).

Confidence: 95% ✓

@dean0x
Copy link
Copy Markdown
Owner Author

dean0x commented May 14, 2026

Review Comments - ambient.test.ts

Lines 405-409: Negative test for old INTENT/DEPTH format

Excellent negative test. The test correctly verifies rejection of the old slash format (e.g., 'Devflow: IMPLEMENT/ORCHESTRATED'). This applies ADR-001 (clean break philosophy -- explicitly verify old format is rejected rather than maintaining backward compatibility).

Confidence: 95% ✓

@dean0x
Copy link
Copy Markdown
Owner Author

dean0x commented May 14, 2026

Code Review Summary - PR #220

APPROVED WITH CONDITIONS

The PR introduces a well-bounded CI Status Gate (Phase 7) with explicit iteration limits and correctly applies ADR-001 (clean break) by removing dead CHAT variant and migrating INTENT/DEPTH format. The changes are sound overall.


Should-Fix Issues (80%+ Confidence)

1. CI Status Gate duplicated across 4 files without enforcement (85%)

Files:

  • shared/skills/implement:orch/SKILL.md:155
  • shared/skills/resolve:orch/SKILL.md:115
  • plugins/devflow-resolve/commands/resolve.md:203
  • plugins/devflow-resolve/commands/resolve-teams.md:250

Issue: The CI Status Gate logic (poll cadence, budget limits, fix attempt count) is replicated verbatim across 4 files. The <!-- SYNC: ci-status-gate --> markers are convention-based with no tooling enforcement. Future changes risk silent drift.

Fix: Add a build-time verification script (scripts/verify-sync-markers.sh) that extracts content between SYNC markers and asserts byte-identical content. This converts the convention into an enforced invariant.


2. CI Status Gate poll/fix loop budget interaction is ambiguous (82%)

Files:

  • shared/skills/implement:orch/SKILL.md:162-164
  • shared/skills/resolve:orch/SKILL.md:124-128
  • plugins/devflow-resolve/commands/resolve.md:214-216

Issue: Step 4 says "max 10 iterations" for a single PENDING poll loop, but step 6 says "max 10 polls across all check/fix cycles combined." If a fix attempt triggers new PENDING, does budget reset per cycle or is it shared? An agent interpreting step 4 literally could consume 10 polls per cycle, violating the global cap intent.

Fix: Clarify that steps 4-5 describe per-cycle behavior but step 6 is the authoritative global cap. Reword step 4: "poll every 60 seconds (budget-limited, see step 6)."


3. Missing negative test for extractIntent with old INTENT/DEPTH format (82%)

File: tests/ambient.test.ts

Issue: The negative test at line 405 verifies hasClassification rejects old INTENT/DEPTH format. However, extractIntent uses the same CLASSIFICATION_PATTERN but lacks explicit verification it also rejects the old format.

Fix: Add companion test case:

it('returns null for old INTENT/DEPTH format', () => {
  expect(extractIntent(textResult('Devflow: IMPLEMENT/ORCHESTRATED'))).toBeNull();
  expect(extractIntent(textResult('Devflow: DEBUG/GUIDED'))).toBeNull();
});

4. Missing SYNC marker content drift detection test (80%)

File: tests/ambient.test.ts

Issue: The CI Status Gate SYNC markers were added to prevent drift, but no test validates that content between <!-- SYNC: ci-status-gate --> markers is identical across all 4 files.

Fix: Add a structural validation test that extracts content and asserts byte-identical matches across implement:orch, resolve:orch, and command files.


5. Missing extractDepth edge case test coverage (80%)

File: tests/ambient.test.ts:420-423

Issue: The extractDepth tests only check canonical outputs. No coverage for casing/whitespace variations or verification that old slash format is not matched.

Fix: Add edge case tests:

it('extractDepth handles casing and whitespace variations', () => {
  expect(extractDepth(textResult('scope: guided'))).toBe('GUIDED');
  expect(extractDepth(textResult('Scope:  ORCHESTRATED'))).toBe('ORCHESTRATED');
});
it('extractDepth does not match old slash format', () => {
  expect(extractDepth(textResult('Devflow: IMPLEMENT/ORCHESTRATED'))).toBeNull();
});

Lower-Confidence Suggestions (60-79%)

SYNC marker scope could be formalized (70%)

The <!-- SYNC: ci-status-gate --> convention is novel to this PR. If more SYNC sections are added in the future, document the convention in CLAUDE.md (what SYNC means, how to verify, what's allowed to differ) to prevent misinterpretation by future contributors.

CI Status Gate variations are not truly identical despite SYNC markers (65%)

The SYNC markers imply content equivalence, but there are intentional context-specific differences (implement:orch vs resolve:orch have different Requires/skip conditions). Consider either: (a) narrowing the SYNC markers to wrap only the shared algorithm (steps 1-6), or (b) renaming to <!-- PATTERN: ci-status-gate --> to communicate "same pattern, adapted to context" rather than "identical content."

CI polling spawns new Git agent per iteration (65%)

The CI Status Gate re-spawns a full Git agent on each of max 10 poll iterations. By design (agents handle all git operations per project conventions), and the 60-second interval makes per-poll overhead negligible. Total of ~12 agent spawns max is reasonable. No action required.


Deduplication Notes

  • Phase numbering: All corrections verified as consistent across implement:orch, resolve:orch, resolve.md, resolve-teams.md, pipeline:orch, plan:orch, and test-driven-development. Zero phase-number drift found.
  • CHAT removal: Verified as dead code (CHAT always QUICK, never emits marker). No remaining CHAT references in codebase.
  • INTENT/DEPTH migration: New test explicitly rejects old format (applies ADR-001). Format migration applied correctly to all skill definitions. Pre-existing references in README.md and CHANGELOG.md are outside this diff's scope (not introduced by these changes).

Overall Score: 8/10

Recommendation: APPROVED FOR MERGE with follow-up PRs to address the 5 should-fix items above.


Review conducted by Devflow code-review system. Multiple specialized reviewers: security, architecture, complexity, performance, consistency, regression, testing, reliability, typescript.

Dean Sharon and others added 5 commits May 14, 2026 18:21
…e feature knowledge base for the Rules System CLI, documenting the architecture, build pipeline, install flow, manifest tracking, and component interactions. Includes constraints, anti-patterns, and gotchas for developers working on rules functionality. Co-Authored-By: Claude <noreply@anthropic.com>
Rename SYNC→PATTERN markers across all 4 copies of the CI Status Gate
(implement:orch, resolve:orch, resolve.md, resolve-teams.md) to accurately
reflect that the copies are the same pattern adapted to context, not
byte-identical content. Context-specific Requires and skip conditions
are moved outside the marker scope.

Remove "max 10 iterations" from step 4 (PENDING branch) in all 4 files
to eliminate the ambiguity where an agent could treat 10 as a per-cycle
cap rather than the global budget declared in step 6. Replace with
"global budget, see step 6" to make the reference explicit.

Also replace hardcoded "proceed to Phase N" references in steps 2-3 with
"proceed to next phase" so the marker body stays valid when surrounded by
differently-numbered phases.

Co-Authored-By: Claude <noreply@anthropic.com>
README.md showed 'Devflow: IMPLEMENT/ORCHESTRATED' as example model
output. The new format since the triage layer introduction is
'Devflow: IMPLEMENT. Loading: devflow:implement:triage.' with triage
emitting 'Scope: ORCHESTRATED'. Update the demo block accordingly so
docs match the actual model output format.

Co-Authored-By: Claude <noreply@anthropic.com>
…sections, and ci-status-gate drift

- extractIntent: add negative test asserting old INTENT/DEPTH slash format returns
  null, mirroring the existing hasClassification negative test (applies ADR-001:
  clean break — explicitly verify old format is not matched)
- extractDepth: add edge cases for casing/whitespace variations (SCOPE_PATTERN uses
  /i flag and \s* so these already pass) and old slash format rejection
- Triage structural: extend existing frontmatter check to also assert each :triage
  skill has '## Scope Assessment' and '## Orchestration Hint Override' sections
- ci-status-gate drift: add structural test extracting the PATTERN block from both
  implement:orch and resolve:orch and asserting steps 2-6 (shared polling logic)
  are identical; step 1 is intentionally context-specific and excluded

Co-Authored-By: Claude <noreply@anthropic.com>
Add runtime sentinel files (.working-memory-disabled, .learning-disabled) so hooks respect enable/disable state independently of hook registration. Extract cross-feature context injection from session-start-memory into a new always-on session-start-context hook. Fix decisions scanner gap in stop-update-memory to gate on the decisions sentinel. Wire CLI enable/disable/status to manage sentinels.

- New hook: session-start-context (always-on, never removed by --disable)

- All 4 memory hooks: check .working-memory-disabled sentinel at startup

- session-end-learning: check .learning-disabled sentinel at startup

- decisions-usage-scan.cjs: check decisions/.disabled sentinel

- init.ts: register session-start-context, manage both sentinels on init

- memory.ts/learn.ts: --enable removes sentinel, --disable creates sentinel

- uninstall.ts: remove session-start-context on uninstall

- 35 new sentinel tests + session-start-context integration tests

task-2026-05-15_1200
@dean0x dean0x changed the title feat: add triage layer and CI status gate feat: sentinel-based disable guards and session-start-context hook May 15, 2026
…entinel tests - Add missing removeDecisionsHook() call in uninstall.ts (pre-existing gap: decisions hook would be left in settings.json after uninstall) - Remove redundant init sentinel tests that only tested fs primitives (writeFileSync/unlinkSync idempotency), not application logic
Comment thread src/cli/commands/init.ts Outdated
return 'missing';
}

// ─── Context hook utilities ────────────────────────────────────────────────
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Architecture Issue (85% confidence): Context hook utilities break Single Responsibility

The addContextHook, removeContextHook, and hasContextHook functions are defined here in init.ts instead of a dedicated module. Every other hook feature (ambient.ts, memory.ts, learn.ts, etc.) follows a consistent pattern: utilities live in their own module, then init imports them.

Suggested fix: Extract to src/cli/commands/context.ts following the same pattern as memory.ts (~80 lines).


Reviewed by devflow code-review agent

Comment thread CLAUDE.md Outdated
**Build-time asset distribution**: Skills and agents are stored once in `shared/skills/` and `shared/agents/`, then copied to each plugin at build time based on `plugin.json` manifests. This eliminates duplication in git.

**Working Memory**: Four shell-script hooks (`scripts/hooks/`) provide automatic session continuity. Toggleable via `devflow memory --enable/--disable/--status` or `devflow init --memory/--no-memory`. UserPromptSubmit (`prompt-capture-memory`) captures user prompt to `.memory/.pending-turns.jsonl` queue. Stop hook captures `response_text` (on `end_turn` only) to same queue, then spawns throttled background `claude -p --model haiku` updater (skips if triggered <2min ago; concurrent sessions serialize via mkdir-based lock). Background updater uses `mv`-based atomic handoff to process all pending turns in batch (capped at 10 most recent), with crash recovery via `.pending-turns.processing` file. Updates `.memory/WORKING-MEMORY.md` with structured sections (`## Now`, `## Progress`, `## Decisions`, `## Modified Files`, `## Context`, `## Session Log`). SessionStart hook → injects previous memory + git state as `additionalContext` on `/clear`, startup, or compact (warns if >1h stale; injects pre-compact memory snapshot when compaction happened mid-session). PreCompact hook → saves git state + WORKING-MEMORY.md snapshot + bootstraps minimal WORKING-MEMORY.md if none exists. Disabling memory removes all four hooks. Use `devflow memory --clear` to clean up pending queue files across projects. Zero-ceremony context preservation.
**Working Memory**: Five shell-script hooks (`scripts/hooks/`) provide automatic session continuity. Toggleable via `devflow memory --enable/--disable/--status` or `devflow init --memory/--no-memory`. Runtime sentinel: `.memory/.working-memory-disabled` — all four memory hooks check this sentinel at startup and exit immediately if present; `devflow memory --enable` removes it, `devflow memory --disable` creates it. UserPromptSubmit (`prompt-capture-memory`) captures user prompt to `.memory/.pending-turns.jsonl` queue. Stop hook captures `response_text` (on `end_turn` only) to same queue, then spawns throttled background `claude -p --model haiku` updater (skips if triggered <2min ago; concurrent sessions serialize via mkdir-based lock). Background updater uses `mv`-based atomic handoff to process all pending turns in batch (capped at 10 most recent), with crash recovery via `.pending-turns.processing` file. Updates `.memory/WORKING-MEMORY.md` with structured sections (`## Now`, `## Progress`, `## Decisions`, `## Modified Files`, `## Context`, `## Session Log`). SessionStart hook (`session-start-memory`) → injects previous memory + git state as `additionalContext` on `/clear`, startup, or compact (warns if >1h stale; injects pre-compact memory snapshot when compaction happened mid-session); gated by `.working-memory-disabled` sentinel. Always-on SessionStart hook (`session-start-context`) → injects cross-feature context (decisions TL;DR, learned behaviors) independently of working memory; sections internally gated by `decisions/.disabled` and `.learning-disabled` sentinels respectively. PreCompact hook → saves git state + WORKING-MEMORY.md snapshot + bootstraps minimal WORKING-MEMORY.md if none exists. Disabling memory removes the four memory hooks (session-start-context is always-on and never removed). Use `devflow memory --clear` to clean up pending queue files across projects. Zero-ceremony context preservation.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Documentation Issue (85% confidence): Hook count inconsistency

The text says "Five shell-script hooks" but then says "all four memory hooks check this sentinel". With the new session-start-context hook, there are now 6 total hooks (5 memory hooks + 1 context hook).

Suggested fix: Clarify the count:

  • Five memory hooks (working memory layer)
  • One session-start-context hook (cross-feature context injection)
  • Total: Six hooks

Reviewed by devflow code-review agent

Comment thread CLAUDE.md
├── .decisions-runs-today # Daily run counter for decisions agent (date + count)
├── .decisions-batch-ids # Session IDs for current decisions batch run
├── .decisions.lock # Lock directory for decisions background agent (transient)
├── .working-memory-disabled # Runtime sentinel — all 4 memory hooks exit immediately if present
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Documentation Issue (88% confidence): Missing decisions/.disabled sentinel in file tree

The .memory/ directory tree documentation shows:

  • .working-memory-disabled
  • .learning-disabled

But it's missing:

  • decisions/.disabled (the sentinel for the decisions agent)

Suggested fix: Add .memory/decisions/.disabled to the file tree list after the decisions-log.jsonl entry.


Reviewed by devflow code-review agent

Comment thread tests/sentinel.test.ts Outdated
hasMemoryHooks,
} from '../src/cli/commands/memory.js';
import {
addLearningHook,
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Code Quality Issue (95% confidence): Unused imports

addLearningHook and hasLearningHook are imported but never used in this test file.

Suggested fix: Remove lines 17-19 to keep imports clean.


Reviewed by devflow code-review agent

Comment thread tests/sentinel.test.ts Outdated
const result = addContextHook('{}', '/home/user/.devflow');
const settings = JSON.parse(result);
expect(settings.hooks?.SessionStart).toBeDefined();
const hasContextHook = settings.hooks.SessionStart.some(
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Code Quality Issue (85% confidence): Variable name shadows imported function

The local variable hasContextHook shadows the imported function of the same name. This makes the code confusing — someone reading the test might think the variable and the function are the same thing.

Suggested fix: Rename the variable to contextHookExists or hasHook to avoid shadowing.


Reviewed by devflow code-review agent

@dean0x
Copy link
Copy Markdown
Owner Author

dean0x commented May 16, 2026

Code Review Summary — Lower Confidence Findings

Inline Comments Created (5 total)

  • Context hook utilities (85% confidence): Architecture issue on init.ts:103
  • Sentinel management repetition (82% confidence): Code quality on init.ts:1227
  • Hook count inconsistency (85% confidence): Documentation on CLAUDE.md:44
  • Missing decisions/.disabled (88% confidence): Documentation on CLAUDE.md:154
  • Unused imports (95% confidence): Code quality on sentinel.test.ts:18
  • Variable shadowing (85% confidence): Code quality on sentinel.test.ts:383

Lower Confidence Findings (60-79%) — Deferred to Summary

These suggestions scored 60-79% confidence and were not posted as inline comments per protocol:

  1. Node.js fallback spawns two separate processes (scripts/hooks/session-start-context:95-102, 83% confidence)

    • The manifest reconciliation invokes node twice rather than once
    • Consider consolidating or documenting performance implications
  2. Sentinel race condition on disable (src/cli/commands/memory.ts:352-355, 82% confidence)

    • CLI --disable creates the sentinel but doesn't drain pending turns queue
    • Consider atomic queue drainage when transitioning disabled state
  3. Fragile error handling with set -e (scripts/hooks/session-start-context:11, 85% confidence)

    • Hook fails hard on any transient I/O error; line 136 (date +%s) is unguarded
    • Suggest explicit error handling for transient file operations

Pre-existing / Out of Scope

  • init.ts is a 1409-line god module (separate refactoring task)
  • Missing test coverage for CLI sentinel enable/disable (separate task)
  • JSON.parse validation gaps (separate security pass)

Reviewed by devflow code-review agent

Dean Sharon and others added 5 commits May 16, 2026 10:20
…e-adds shared/rules/reliability.md to the referencedFiles array in .features/index.json so staleness detection for the cli-rules knowledge base correctly tracks changes to that file. Co-Authored-By: Claude <noreply@anthropic.com>
- Working Memory paragraph: clarify 'Four shell-script hooks' (not five)
 with parenthetical noting session-start-context is the always-on fifth
- Decisions agent paragraph: add Runtime sentinel sentence for
 .memory/decisions/.disabled, matching Learning agent paragraph symmetry
- .memory/ file tree: add .disabled sentinel entry to decisions/ subtree

Co-Authored-By: Claude <noreply@anthropic.com>
- Create src/cli/commands/context.ts with addContextHook/removeContextHook/hasContextHook
  extracted from init.ts (SRP: each hook feature in its own module)
- Create src/cli/utils/sentinel.ts with manageSentinel() to eliminate 6 copies
  of the identical enable/disable sentinel pattern across init.ts, memory.ts, learn.ts
- Update init.ts: import from context.ts and sentinel.ts; 4 sentinel blocks collapsed
  to a single manageSentinel call each; re-export context utilities for backward compat
- Update memory.ts: use manageSentinel; add best-effort queue drain on --disable
  (removes .pending-turns.jsonl and .pending-turns.processing orphans)
- Update learn.ts: use manageSentinel for --enable and --disable sentinel management
- Update uninstall.ts: import removeContextHook from context.ts (canonical source)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused imports (addMemoryHooks, removeMemoryHooks, hasMemoryHooks,
  addLearningHook, hasLearningHook); new CLI sentinel tests use manageSentinel
  directly per architecture context
- Extract parseHookOutput() helper with structural assertions before property
  access, replacing bare JSON.parse().property chains throughout
- Rename local 'hasContextHook' variables to 'hookPresent' to eliminate
  shadowing of the imported function of the same name
- Add side-effect assertion to background-memory-update sentinel test (lock
  directory must not be created when disabled) plus a positive-path test
- Fix conditional assertion in 'skips learned behaviors' test — add explicit
  else branch so the test never silently passes; fix same pattern in
  'session-start-memory no longer outputs decisions TL;DR'
- Add Part E: manageSentinel utility tests covering create, parent-dir creation,
  remove, idempotent enable, idempotent disable, and disable→enable lifecycle
- Add Part F: sentinel existence check tests that verify the boolean logic
  backing the runtime-disabled warnings in memory --status and learn --status

Co-Authored-By: Claude <noreply@anthropic.com>
…s - Remove unused gitRoot parameter from manageSentinel — only sentinelPath was ever used; dead parameter added noise to all 8 call sites - Remove Part F test block (4 tests) that tested fs.promises.access() behavior, duplicating Part E coverage via fs.existsSync Co-Authored-By: Claude <noreply@anthropic.com>
@dean0x dean0x merged commit dc77db5 into main May 16, 2026
4 checks passed
@dean0x dean0x deleted the feature/triage-layer-ci-gate branch May 16, 2026 09:26
dean0x added a commit that referenced this pull request May 26, 2026
## Summary

Implements ambient mode for Devflow — a zero-overhead session
enhancement system with plan auto-detection and command awareness.
Ambient mode consists of two independent, toggleable components:

1. **Plan Auto-Detection**: UserPromptSubmit hook detects structured
implementation plans (marked with `## Goal`, `## Steps`, `## Files`) and
emits a directive to invoke `devflow:implement` via the Skill tool.
2. **Command Awareness**: Always-on rule installed to
`~/.claude/rules/devflow/commands.md` documents available
`/devflow:<name>` commands and the auto-execution trigger.

## Key Features

- **Zero Overhead**: Plan detection hook only outputs when a plan is
detected; normal prompts are unaffected
- **Toggleable**: Enable/disable via `devflow ambient
--enable/--disable` or `devflow init`
- **Independent Components**: Can be configured separately
- **Passive Reference**: Commands rule provides documentation without
changing behavior

## Implementation Details

- Ambient mode state stored in manifest `features.ambient: boolean`
- Hook implementation via `preamble` hook for plan detection
- Commands rule managed directly by `ambient.ts` command (not through
rules plugin system)
- SessionStart hook injects plan marker context if plan is detected in
current session
- Feature toggleable separately from other Devflow systems (memory,
learning, decisions, knowledge, rules)

## Testing

Added comprehensive tests covering:
- Hook addition/removal lifecycle
- Rule file creation with stable content hash
- Ambient mode enable/disable transitions
- Edge cases (already enabled, already disabled, invalid states)
- Cleanup of stale hooks/rules

Closes #220

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Dean Sharon <deanshrn@gmain.com>
Co-authored-by: Claude <noreply@anthropic.com>
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.

1 participant