Skip to content

Troubleshooting

Read the block, not just the verdict. Every denial carries four facts:

✗ Denied by CC
zone schema · risk high
owner paulo@commitcycle.com
task CC-42 declared api, web
reason path is in a zone the task never asked for
  • The zone and its risk — what boundary you hit.
  • The owner — a person, not a policy. They can open it.
  • What your task declared — the mismatch is usually the answer: the task was scoped without this zone, and the scoping might simply be wrong.
  • The way forwardcycle request-access --zone <id> --mode write --reason "…" --alternative "…". One approval, a TTL, and the write lands. --alternative is mandatory — the CLI refuses the ask without it — because the approver deserves to know what happens on “no”.

What not to do is copy the file somewhere unprotected, edit it there and move it back. The closing gate compares the whole diff against declared zones, so the workaround surfaces at close — later, with less context, and looking worse than the request would have.

The refusal names no zone, and the path is one the zone map never mentions:

✗ Denied by CC
no task is active on this branch — start one so the change is on the record.
Nothing about this path is protected. The problem is that there is no task on
this branch, so the change would have nowhere to be recorded.

With no task bound to the branch, nothing is writable — not only the protected paths. A zone map decides which task may write where; the task itself is what makes a write recordable at all, and a change with nowhere to be recorded is the one thing the product does not allow. This is the same rule on a branch with no task, on main, and on a branch whose grant has expired.

The way out is the ordinary one: cycle start "<what you are about to do>" … to file and scope it, or cycle start CC-42 to adopt a task the board already holds. If the work genuinely is not a task — a scratch file, a note to yourself, an export you are about to throw away — write it outside the repository, where CC has no opinion.

It catches people twice in particular: just after a hand-in, because cycle submit revokes the grant and clears the block, so the branch you are standing on has no task any more; and eight hours in, when the grant’s TTL runs out mid-session. Both read as the tool breaking and are the tool working.

The two have different ways out, and the second one used not to have any.

“The grant expired” — eight hours in, mid-task

Section titled ““The grant expired” — eight hours in, mid-task”

cycle status and cycle doctor both name it:

The grant expired at 2026-09-06T17:12:04.881Z — that is why writes stopped.
Run `cycle renew`: it asks the board for the same grant again — the same zones, a new
expiry — and can never widen it.

Run cycle renew. It re-issues the grant this task already holds: the same zones, the same modes, the same branch, a new expiry. It cannot widen anything — the board re-issues what the grant carried, not what the task now declares — and a high-risk zone whose approval was withdrawn or timed out is refused, exactly as it would be at the gate. Every renewal is recorded with your name on it and appears in the task’s audit record.

It works on a board with one member, where there is nobody to ask (D-33). With more people on the board it says so and names the path that is theirs: cycle pause <task> --reason "…" hands the grant back, and cycle start <task> re-earns it at the gate.

Do not reach for cycle start here. It refuses to run with uncommitted changes — which is to say it refuses in exactly the state eight hours of work produces — and the refusal it prints is about the working tree or the state machine, not about the expiry you were actually trying to fix.