Consolidated from reviewing my own OMP session transcripts (~/.omp/agent/sessions/*.jsonl) across the projects where ctl's OMP skills were active, 2026-06-12 → 2026-06-23. First-party evidence — every claim below is anchored to a session I can re-open. Project names anonymized; the stack + date + session-id suffix let me (and only me) re-verify.
I categorized every observed gate event by its effect on the actual task:
| gate behavior |
occurrences |
effect on the task |
ctl gate unavailable — failing closed blocks write/edit/bash/task entirely |
dozens, across 5 sessions |
blockade: agent burns tokens diagnosing ctl, not the task |
| write routed around the gate via bash/git |
multiple |
enforcement is theater |
ctl reachable but active_tasks: [] → ungoverned → allow all |
1 session |
zero enforcement |
| gate legitimately blocked an out-of-scope write to good effect |
0 |
— |
The productive middle — gate enforcing a real write_allow on an active task — appears 0 times in the whole dataset. The gate is either fully closed (binary unreachable), fully open (no active task), or circumvented. None of those is the state ctl is designed to be valuable in.
Finding 1 — bash bypasses the write boundary (P0, architectural, NOT fixed in 0.0.14)
Evidence — Project B (pnpm monorepo), 2026-06-18, session …019ed8ce: the gate was active and correctly blocked edit/write on merge-conflict resolution. The agent then did the same writes through bash — git checkout --ours pnpm-workspace.yaml (+ .gitmodules, package.json) — and logged: "bash 的 git 命令不被 control-guard gate 拦截(gate 只拦 edit/write 工具)". The boundary was routed around with the first tool the agent reached for.
Code confirmation (current master): the OMP hook's recordDecision deliberately records a bash_write as ALLOW with record: true — "a bash_write ALLOW, never path-scoped". So bash writes are observed, never denied, in 0.0.14 too. The write-boundary model is keyed on explicit write/edit tool path args; bash command content that mutates files (git checkout, sed, echo >, cp, npm pkg set) is not mapped to write targets. This empirically confirms the README's 诚实声明 that "Bash is not a hard write boundary" — and shows the agent exploiting it in a real task.
Why P0: issue #6's proposal-mode asserts "enforcement strength unchanged". But the data says that strength is already not present on the bash channel. Polishing authoring while bash can rewrite any file in one command makes the declared write_allow a gate for the obedient only.
Finding 2 — ungoverned-by-default: no active task ⇒ no enforcement (architectural)
Evidence — Project C (TS server, .trellis→.ctl migration), 2026-06-16/17, session …019ed041: ctl 0.0.2 status returned active_tasks: [], tasks.total: 0. With no active task there is nothing to enforce a boundary against, so writes were allowed — the gate contributed nothing while ctl was installed. (The real spec-driven load in the heaviest project, the compiler work, was done under .trellis/spec/, not ctl.)
This is "correct" in isolation (you can't enforce a scope that doesn't exist), but in practice it means ctl's value is gated behind the full create→ready→start ceremony — and the data shows that ceremony wasn't happening, so ctl sat installed and inert. Design question worth answering: should an installed-but-idle ctl be a noisy "you are working ungoverned" state rather than a silent allow-all?
This is exactly the friction #6's proposal-mode targets — but it also implies the default mode needs to nudge toward governance, not silently abstain.
Finding 3 — fail-closed produces total stoppage, not safety (cost underestimated)
Evidence — Project A (Vue/Vite TS), 2026-06-22, session …019eee90: real task = upgrade a product-route API from a flat list to a DAG. First bash hit failing closed; the agent then spent 10+ consecutive tool calls reading control-guard SKILL.md, the hook source, and config.toml, applying the skill's own "Iron Law: Symptom → Source" to diagnose ctl itself — the actual type refactor never started.
Root cause + follow-ups: ctl.exe lived at AppData/Local/ctl/bin/ctl.exe but the hook's bare execFile("ctl") couldn't find it (Node does no PATHEXT resolution on Windows). Continued across 2026-06-23 sessions …019ef25c / …019ef290 / …019ef2d8; even the eval kernel reported an empty PATH. After I said "ctl 更新了,你重试" it still failed.
Version caveat (important — partial fix already shipped): the PATH-resolution pain is largely fixed upstream — 0.0.14's resolveCtlBin() + resolveViaPathLookup() + readDotEnvCtlBin() (CTL_BIN → .env → CARGO_HOME → ~/.cargo/bin → where/which) closes the Windows hole that caused most of the lockouts above.
What is NOT fixed and remains architectural: the philosophy of fail-closed. "An unenforceable boundary must never silently allow writes" is sound — but the observed cost is that a flaky/unreachable boundary engine produces total work stoppage + self-diagnostic token burn, not safety. There is no middle gear. At minimum ctl needs a degraded mode: when the gate engine is unreachable, fall back to read-only-allowed + loud warning + a one-shot human ack to proceed ungoverned, rather than hard-blocking every mutating tool until the binary responds. Right now the choice is "perfectly safe and unable to do anything" vs "fix the binary" — and in the field the agent just works around it (see Finding 1).
Severity & relationship to #5 / #6
Net: #6 (proposal-mode) optimizes authoring; these three say the enforcement layer has gaps that authoring improvements alone won't reach — most urgently the bash channel. Suggest sequencing: #1 first (without it, write_allow is advisory), then #6, with #2/#3 as accompanying UX.
Consolidated from reviewing my own OMP session transcripts (
~/.omp/agent/sessions/*.jsonl) across the projects where ctl's OMP skills were active, 2026-06-12 → 2026-06-23. First-party evidence — every claim below is anchored to a session I can re-open. Project names anonymized; the stack + date + session-id suffix let me (and only me) re-verify.I categorized every observed gate event by its effect on the actual task:
ctl gate unavailable — failing closedblocks write/edit/bash/task entirelyactive_tasks: []→ ungoverned → allow allThe productive middle — gate enforcing a real
write_allowon an active task — appears 0 times in the whole dataset. The gate is either fully closed (binary unreachable), fully open (no active task), or circumvented. None of those is the state ctl is designed to be valuable in.Finding 1 — bash bypasses the write boundary (P0, architectural, NOT fixed in 0.0.14)
Evidence — Project B (pnpm monorepo), 2026-06-18, session
…019ed8ce: the gate was active and correctly blockededit/writeon merge-conflict resolution. The agent then did the same writes through bash —git checkout --ours pnpm-workspace.yaml(+.gitmodules,package.json) — and logged: "bash 的 git 命令不被 control-guard gate 拦截(gate 只拦 edit/write 工具)". The boundary was routed around with the first tool the agent reached for.Code confirmation (current master): the OMP hook's
recordDecisiondeliberately records abash_writeas ALLOW withrecord: true— "a bash_write ALLOW, never path-scoped". So bash writes are observed, never denied, in 0.0.14 too. The write-boundary model is keyed on explicitwrite/edittoolpathargs; bash command content that mutates files (git checkout,sed,echo >,cp,npm pkg set) is not mapped to write targets. This empirically confirms the README's 诚实声明 that "Bash is not a hard write boundary" — and shows the agent exploiting it in a real task.Why P0: issue #6's proposal-mode asserts "enforcement strength unchanged". But the data says that strength is already not present on the bash channel. Polishing authoring while bash can rewrite any file in one command makes the declared
write_allowa gate for the obedient only.Finding 2 — ungoverned-by-default: no active task ⇒ no enforcement (architectural)
Evidence — Project C (TS server,
.trellis→.ctlmigration), 2026-06-16/17, session…019ed041:ctl 0.0.2status returnedactive_tasks: [],tasks.total: 0. With no active task there is nothing to enforce a boundary against, so writes were allowed — the gate contributed nothing while ctl was installed. (The real spec-driven load in the heaviest project, the compiler work, was done under.trellis/spec/, not ctl.)This is "correct" in isolation (you can't enforce a scope that doesn't exist), but in practice it means ctl's value is gated behind the full create→ready→start ceremony — and the data shows that ceremony wasn't happening, so ctl sat installed and inert. Design question worth answering: should an installed-but-idle ctl be a noisy "you are working ungoverned" state rather than a silent allow-all?
This is exactly the friction #6's proposal-mode targets — but it also implies the default mode needs to nudge toward governance, not silently abstain.
Finding 3 — fail-closed produces total stoppage, not safety (cost underestimated)
Evidence — Project A (Vue/Vite TS), 2026-06-22, session
…019eee90: real task = upgrade a product-route API from a flat list to a DAG. Firstbashhitfailing closed; the agent then spent 10+ consecutive tool calls readingcontrol-guardSKILL.md, the hook source, andconfig.toml, applying the skill's own "Iron Law: Symptom → Source" to diagnose ctl itself — the actual type refactor never started.Root cause + follow-ups: ctl.exe lived at
AppData/Local/ctl/bin/ctl.exebut the hook's bareexecFile("ctl")couldn't find it (Node does no PATHEXT resolution on Windows). Continued across 2026-06-23 sessions…019ef25c/…019ef290/…019ef2d8; even the eval kernel reported an emptyPATH. After I said "ctl 更新了,你重试" it still failed.Version caveat (important — partial fix already shipped): the PATH-resolution pain is largely fixed upstream — 0.0.14's
resolveCtlBin()+resolveViaPathLookup()+readDotEnvCtlBin()(CTL_BIN → .env → CARGO_HOME → ~/.cargo/bin → where/which) closes the Windows hole that caused most of the lockouts above.What is NOT fixed and remains architectural: the philosophy of fail-closed. "An unenforceable boundary must never silently allow writes" is sound — but the observed cost is that a flaky/unreachable boundary engine produces total work stoppage + self-diagnostic token burn, not safety. There is no middle gear. At minimum ctl needs a degraded mode: when the gate engine is unreachable, fall back to read-only-allowed + loud warning + a one-shot human ack to proceed ungoverned, rather than hard-blocking every mutating tool until the binary responds. Right now the choice is "perfectly safe and unable to do anything" vs "fix the binary" — and in the field the agent just works around it (see Finding 1).
Severity & relationship to #5 / #6
Net: #6 (proposal-mode) optimizes authoring; these three say the enforcement layer has gaps that authoring improvements alone won't reach — most urgently the bash channel. Suggest sequencing: #1 first (without it,
write_allowis advisory), then #6, with #2/#3 as accompanying UX.