feat(reflexes): port 5 passive rules from fs-cortex + idempotent merger#12
feat(reflexes): port 5 passive rules from fs-cortex + idempotent merger#12NestorPVsf wants to merge 1 commit into
Conversation
Ports 5 non-duplicate reflexes from fermontero/fs-cortex (MIT) into the Sinapsis passive-rules tier: - read-before-edit: verify file was Read before Edit/Write - test-after-change: reminder to run tests after code edits - git-push-safety: pre-push fetch+rebase, --force-with-lease - git-merge-verify: pre-merge CI checks + cleanup - instinct-downvote: adapted from /cx-downvote to Sinapsis /downvote Skipped 5 duplicates (env-never-commit, git-commit-quality, api-auth-check/reminder, security-headers, capture-decision). Implementation: - seeds/reflexes.json: 5 rules + MIT attribution - core/_reflex-merge.mjs: idempotent merger, user customizations win, atomic write preserves 0600 mode - install.sh / install.bat: Step 5c runs the merger after hook scripts - tests/test-reflexes.sh: 11 TDD tests (11/11 GREEN) incl. regression guard that test-after-change does NOT fire on Read/Grep Codex review fixes applied pre-commit: - P1: install.bat now mirrors install.sh reflex step - P2: merger preserves existing chmod 0600 - P2: test-after-change scoped to ^(Edit|Write) so Read/Grep dont fire Suite: 116 → 127 GREEN, 0 regressions. Credit: Fernando Montero (github.com/fermontero/fs-cortex, MIT).
Luispitik
left a comment
There was a problem hiding this comment.
Verified empirically and the quality is above the bar: your 11 tests pass 11/11 on Windows Git Bash (Node 24), cygpath/mktemp/USERPROFILE are handled correctly, the merger works against main's real _passive-rules.json (6→11), all 5 rules fire through the v4.6.1 activator (byte-identical to your base — no functional drift), and the atomic write even preserves the file's 0600 mode. Scope is fine too: the passive-rules tier is core product (6 default rules documented in FEATURES.md), not engineering tooling.
The blocker is staleness, not substance — git merge-tree confirms conflicts in 4 files (CHANGELOG.md, docs/FEATURES.md, install.sh, install.bat), and v4.5.0 was meanwhile released in main for the Opus 4.7 integration, so the version number collides semantically as well. Asks:
- Rebase onto main (v4.6.1) — when resolving
install.sh/install.bat, keep the_precompact-guard.shcopy and the hook-count text that v4.5 introduced. - Renumber to the next free version and update the 'v4.5' references in
_reflex-merge.mjs,seeds/reflexes.json, both installers anddocs/FEATURES.md. Refresh the '116 → 127 passing' badge — the suite has grown since your base. - Register the tests in CI: add a
bash tests/test-reflexes.shstep to.github/workflows/tests.yml(the existing ubuntu/macos/windows matrix is ideal for validating the cygpath handling). - Drop (or justify and downgrade)
read-before-edit: Claude Code already enforces Read-before-Edit at the harness level, so the rule injects ~25 redundant tokens on every Edit/Write and occupies 1 of the activator's 3 slots — a single Edit onroute.tsalready saturates the cap (verified: api-auth-reminder + read-before-edit + test-after-change). - Create the tmp file already protected:
fs.writeFileSync(tmp, text, { mode: 0o600 })instead of write-then-chmod — closes the umask window on a fileinstall.shdocuments as personal data. - Minor: unify the
Step 5cvsStep 5dcomment inconsistency after the rebase, and haveinstall.batcheckerrorlevelafter invoking the merger and WARN on failure (install.sh's|| truedegrades gracefully, but silently — a one-line warning would help). - Found while testing:
instinct-downvoteis nearly inert — the activator is PreToolUse and only seestool_name/tool_input, never the user's chat, so in practice it fires only when the user already ran/downvote(viafile_path commands/downvote.md), making the inject redundant. Prune it or rethink the trigger during the rebase. Same spirit fortest-after-change: it fires before the edit, so wording like "You are about to modify test/route code — plan to run the suite after" is more honest about the moment of injection.
After the rebase this merges. Thanks for the cross-OS care — it shows.
|
Ping @NestorPVsf — same situation as #9: substance was verified above the bar in the 2026-06-10 review, the blocker is only staleness (rebase onto main — now v4.6.2 —, renumber, CI registration, plus the smaller asks). If you don't have bandwidth, tell us and we'll close and track it in an issue; default in ~2 weeks if there's no activity. |
Critical fixes: - Luispitik#1-3: install.sh preserves user data on upgrade (instincts, rules, projects) - Luispitik#4/5A: execSync → execFileSync in 3 hooks (command injection prevention) - Luispitik#5: auto-promote works — drafts track occurrences without injecting - Luispitik#6: race condition — instinct-activator checks dream lock before write Security fixes: - #5B: +4 secret scrubbing patterns (JWT, GitHub, AWS, PEM) in observe_v3.py - #5C/Luispitik#12: ReDoS protection — reject nested quantifiers before RegExp - #5D: chmod 600 on data files during install - #5E/Luispitik#7: fcntl.flock() on JSONL append and rotation - #5F: inject sanitization — 500 char limit + blocked prompt injection patterns Bug fixes: - Luispitik#8: token catalog corrected (9,995 vs 2,700 declared) - Luispitik#9: install.bat synced to v4.3.1 with missing hooks - Luispitik#10-11: instinct-status + passive-status use actual schemas - Luispitik#13: Jaccard Unicode support (\p{L}\p{N}) - Luispitik#14: contradiction detection — \bdo\b scoped to actionable verbs - Luispitik#15: session-end documents relationship with /eod - Luispitik#16: tmpdir flag cleanup (>24h stale files) - Luispitik#17: session-learner selects most recent project by mtime - Luispitik#18: operator-state schema validation flag - Luispitik#19: KNOWLEDGE_FILE dead code removed - Luispitik#20: synapis → sinapsis directory naming + catalog IDs - Luispitik#22: SINAPSIS_DEBUG=1 redirects stderr to debug log Tests: 51/51 GREEN (15 install + 11 security + 25 dream cycle) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Ports 5 non-duplicate passive rules (reflexes) from fermontero/fs-cortex (MIT) into the Sinapsis passive-rules tier. Adds an idempotent merger so fresh installs and upgrades both receive the new rules while preserving any user customizations.
Ported (5)
read-before-edit^(Edit|Write)\stest-after-change^(Edit|Write)\s.*(\.test\.|...)git-push-safetygit push|gh pr create--force-with-leasegit-merge-verifygh pr merge|git mergeinstinct-downvote/downvote|wrong instinct|.../downvoteon negative feedback (adapted from fs-cortex/cx-downvoteto Sinapsis's native/downvote)Skipped as duplicates (5)
env-never-commit,git-commit-quality,api-auth-check(→api-auth-reminder),security-headers(→security-headers-check),capture-decision(→decision-capture). Sinapsis equivalents kept as-is.Changes
seeds/reflexes.json(new): 5 rules +_credit/_licenseheader.core/_reflex-merge.mjs(new, ~100 LOC Node.js): idempotent merger, user id wins on conflict, atomictmp → renamewrite that preserves 0600 file mode (install.sh hardens_passive-rules.jsonto 0600; the merger must not relax to umask). CLI flags:--seeds-path,--index-path,--dry-run.install.sh+install.bat: new Step 5c runs the merger after hook scripts.tests/test-reflexes.sh(new): 11 TDD tests including activator-integration (rules actually fire) and a regression guard thattest-after-changedoes NOT fire on Read/Grep.Codex review fixes applied pre-commit
/codex:review --base mainflagged 3 issues, all addressed before this PR:test-after-changefired on Read/Grep because trigger only tested filename. Scoped to^(Edit|Write)\s.*. Regression test added.Test plan
bash tests/test-reflexes.sh→ 11/11 GREEN (including regression guard)seeds/reflexes.jsonbash -nsyntax oninstall.shtest-after-changedoes NOT fire on Read/Grep/codex:reviewsecond-opinion appliedIndependence
Branches from
main(45949ed). No dependency on PR #7 (dashboard), PR #8 (seeds), or PR #9 (laws). Can merge in any order.Credit
5 rules ported from fermontero/fs-cortex — MIT © 2026 Fernando Montero. Attribution preserved as
origin: seed:fermontero-fs-cortexin each rule.