Skip to content

docs+fix: reconcile stale docs with shipped M4–M6+V1 surface; wire approval_expired; prune dead logic - #3

Merged
neostfox merged 4 commits into
masterfrom
docs-logic-audit-fixup
Jun 19, 2026
Merged

docs+fix: reconcile stale docs with shipped M4–M6+V1 surface; wire approval_expired; prune dead logic#3
neostfox merged 4 commits into
masterfrom
docs-logic-audit-fixup

Conversation

@neostfox

Copy link
Copy Markdown
Owner

Project-wide review pass: update outdated docs to match the actual shipped surface, and handle fractured/dead code logic. Code was already healthy (clean build, clippy clean), so the bulk of the drift was documentation.

Documentation (drift vs actual CLI/code)

  • DESIGN.md — telemetry/drift/control.json are shipped (M5 ✅), not "规划中"; status snapshot now M0–M6 + V1 (not "stops at M3"); replaced the dead control * command namespace with real commands (ctl board/report/drift/agent-report/run ingest); fixed superseded module layout and the "OpenCode planned" claim.
  • ROADMAP.md — fixed the dogfood workflow (control statusctl board; wrong --mode/--title/--scope/--gate flags → real task create syntax); removed non-existent ctl assignment create; ctl adapter capabilities omp--adapter omp; refreshed TaskDefinition (depends_on, kind); added a V1 cognitive-layer section + a 已知缺口 section; marked the review-rule distribution gap ✅ resolved (verified the include_str! fix is present).
  • GLOB_WORKFLOW.md / AGENTS.md / REPORT.mdcontrolctl; corrected binary name / milestone scope / "gates stubbed" / dependency list / protected-paths set; reconciled REPORT.md Finding 5 self-contradiction.

Code

  • Wired approval_expired — added expire_stale_approvals (mirrors the tested expire_stale_leases), called in workspace_apply, so an expired approval is now recorded as an event instead of only lazily read as invalid. Schema-correct payload (only request_id), idempotent, + a new test.
  • Removed dead field RunInfo.started_at_seq (written, never read).
  • Removed a dead branch — the always-true if spec_dir.exists() in cmd_hook_spec_status.
  • Fixed a stale binary name in a user-facing error string (control approval grantctl approval grant).
  • Documented deferred scaffolding (M6 task-level run-event mirror; run-scoped gate/evidence duplicates) as forward-looking — not wired, because emitting them alongside the canonical AgentRun aggregate would create a second, conflicting source of truth (STATE-006).

Verification

  • 417 tests pass (416 baseline + 1 new); cargo fmt --check and cargo clippy --all-targets clean.
  • Performed under the repo's own ctl governance (task docs-logic-audit-fixup, gates cargo_check/cargo_test PASS).

🤖 Generated with Claude Code

neostfox and others added 4 commits June 18, 2026 23:51
First slice of the PRD→tasks workflow: scaffold the shape, not the
decomposition. `ctl prd init [--title <t>]` prints a structured PRD template
to stdout (`ctl prd init > prd.md`) for the grill/LLM step to fill.

The template's `## Tasks` section is a deliberate, parseable convention —
id / objective / write-allow / gates per vertical task — so a later
`ctl prd plan` step can map each item to a `ctl task create`. The "grill"
(requirement interrogation) is an LLM activity, not ctl-core; ctl owns only
the deterministic shape.

Test pins the section headers, per-task field keys, and title substitution so
the convention can't silently drift before the parser lands. Verified live:
`prd init --title "Payments v2"` emits the filled template.

Task: workflow-prd-to-tasks-v1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ralph-safe-run-v1, scoped as a principled adjustment. A true "loop an executor
unattended" command would violate ctl's core invariant (it never spawns an
executor) and needs a run/executor lifecycle that doesn't exist yet — the same
root cause as the lease-TTL deferral. So this ships the part of a bounded
autonomous loop that is real and safe today: the governance envelope, not the
executor.

`ctl ralph run --id <task>` loops a READ-ONLY GO/NO-GO safety check with three
independent hard stops — a kill-switch file, a wall-clock deadline (--max-secs),
and a max-cycle cap (--max-iters) — and halts the instant the check reports
NO-GO. It spawns nothing and writes no code; the agent keeps running in the
operator's own loop, with ralph as the dead-man's-switch around it.

ralph_safety_check composes this session's guards into one verdict: task
hold/terminality, cross-ledger consistency (cross_ledger_findings), shared-.git
locks (scan_shared_git_risk), and drift (next_action != Pass). All read-only.

Tests: GO on a clean active task, NO-GO on a terminal task, NO-GO on a global
cross-ledger inconsistency. Verified live: GO cycles then max-iters stop on an
active task; immediate NO-GO on a terminal task; kill-switch stops at 0 cycles.

Deliberately NOT built (needs executor lifecycle + explicit risk sign-off):
spawning/looping an actual unattended executor.

Task: ralph-safe-run-v1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gives run-lease TTL real teeth without crossing the lines that made it
report-only. Previously `ttl_seconds` was stored but never enforced: the run
reducer had no `lease_expired` transition, and `recover` only reported
`lease_stale`. (max_uses was already enforced via consume().)

- Run reducer: add the `lease_expired` transition (Active→Expired), idempotent,
  mirroring lease_revoked. The wall-clock judgement stays OUT of the
  deterministic reducer.
- `ctl run expire-lease --run <id> [--apply]`: explicit, operator-invoked. It
  appends `lease_expired` ONLY when the lease is genuinely past its wall-clock
  TTL (age from the lease_created event's occurred_at, same source as
  recover's lease_stale). Refuses a within-TTL or non-active lease; preview by
  default. The staleness check is read at the application layer, never auto in a
  read path — replay stays deterministic, the recorded event carries its own
  occurred_at.

Deliberately NOT done (unchanged from the deferral rationale): no auto-expiry,
no process termination. Expiring a lease does not wind the run down — that
remains `run recover --abort`. ttl_exceeded() is a pure, unit-tested helper.

Tests: 9 — reducer (expire transition + no-lease error), ttl_exceeded
(strict-greater, saturating), and expire_run_lease (stale→expired, preview
no-mutate, within-ttl refuse, no-native-lease) via an injected clock. Verified
live: aborted run → not_active, fresh scheduled run → within_ttl (age 0/ttl 3600).

Task: capability-lease-ttl-enforce-v1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…proval_expired; prune dead logic

Project-wide review pass.

Docs (drift vs actual CLI/code):
- DESIGN.md: telemetry/drift/control.json are shipped (M5), not "规划中"; status
  snapshot now M0-M6+V1, not "stops at M3"; replace dead `control *` namespace with
  real `ctl board/report/drift/agent-report/run ingest`; fix module layout + opencode.
- ROADMAP.md: fix dogfood workflow (control status -> ctl board; real `task create`
  flags); drop non-existent `ctl assignment create`; `capabilities omp` -> `--adapter`;
  refresh TaskDefinition (depends_on, kind); add V1 section + 已知缺口; mark
  review-rule distribution gap resolved (include_str! verified).
- GLOB_WORKFLOW.md / AGENTS.md / REPORT.md: control -> ctl; binary/scope/gate/dep
  corrections; reconcile REPORT Finding 5 self-contradiction.

Code:
- Wire approval_expired: add expire_stale_approvals (mirrors expire_stale_leases),
  called in workspace_apply, so expiry is recorded as an event instead of only lazily
  read as invalid. Schema-correct payload, idempotent, + test.
- Remove dead field RunInfo.started_at_seq (written, never read).
- Remove always-true `if spec_dir.exists()` dead branch in cmd_hook_spec_status.
- Fix stale `control approval grant` -> `ctl approval grant` in error string.
- Document deferred reducer scaffolding (M6 task-level run mirror; run-scoped
  gate/evidence duplicates) as forward-looking, not dead code.

417 tests pass; cargo fmt + clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@neostfox
neostfox merged commit 673667f into master Jun 19, 2026
2 of 4 checks passed
@neostfox
neostfox deleted the docs-logic-audit-fixup branch June 19, 2026 04:59
neostfox added a commit that referenced this pull request Jun 20, 2026
gate-decision-log-v1 (audit A1 / sharpest-three #3). The gate computed
allow/deny verdicts but recorded none of them — the audit trail had a hole
exactly at the enforcement point. Wire the existing `ctl hook record-decision`
into all three host gate hooks so blocked/flagged calls become evidence.

- ctl: `record-decision` now stamps `canonical: false` on every entry (testable
  `decision_entry`); new `ctl decisions [--limit N] [--json]` viewer renders the
  log behind a prominent NON-CANONICAL banner (testable `format_decisions`).
- gate: the bash_write verdict carries `record: true` (a bash write is never
  path-scoped, so every attempt is noteworthy).
- hooks (.claude py / .omp ts / .opencode ts): after the gate verdict, record
  when `!allowed || record` — every deny plus bash_write allows. Best-effort and
  non-blocking: an advisory log must never break the gate it observes.
- tests: Rust unit tests for the label/format/limit/empty/json paths; opencode
  bun tests for shouldRecord / buildRecordArgs and the record-on-deny /
  record-on-bash_write / no-record-on-plain-allow wiring.

The log is non-canonical evidence: not a task event, not hash-chained, not
covered by `ctl validate`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
neostfox added a commit that referenced this pull request Jul 26, 2026
…cript

Updates the V1 cognitive-layer bullet (ctl spec fact ✅ -> 'knowledge/memory layer
externalized'), the memory-carrier table (atomic facts writer is now
scripts/knowledge.py fact add), marks #1/S + #2/S done, and reframes the remaining
memory-system backlog (#3/#4/#5/#6) to target scripts/knowledge.py instead of the
removed ctl memory / ctl spec fact commands — consistent with the decision that
ctl Rust stays governance-only and the knowledge layer is workflow-side.
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