feat: CEO Phase 3 — decision-guidance redlines (CEO drafts, board ratifies) #250

Merged
joshtronic merged 2 commits from feat/ceo-mandate-redline into master 2026-06-25 19:34:46 +00:00
Collaborator

CEO Phase 3 — decision-guidance redlines (the layer's 100%)

The mandate-as-living-board-document, fully realized: the CEO drafts mandate edits, the board ratifies by merging. No board member files their own mandate edits.

How it works:

  • The weekly pass gathers the board's verdicts on its prior proposals — greenlit (Agent-labeled) / declined (closed) / pending (ceo_proposal_outcomes) — and folds them into the prompt.
  • When those reveal a clear, durable pattern, the model ends its response with a ===GUIDANCE=== line (parsed into .guidance). No signal → nothing.
  • The harness opens a PR appending that entry to a ## Decision guidance section in CEO.md (ceo_open_guidance_pr — contents-API + new_branch, no clone), assigned to you to merge. Over weeks, CEO.md accumulates "how Josh actually decides," the CEO reads its own mandate, and asks less.

Safety posture (unchanged):

  • Append-only — it adds what it learned, never rewrites or erases existing guidance. A bad entry is at worst a bullet you decline.
  • Throttled to one open guidance PR (ceo_guidance_pr_open) — redlines never stack.
  • The CEO still never commits to master or merges — it drafts (issues + redline PRs), the board ratifies. Same "propose, you ratify" line as Phase 2.

Validated: unit tests for the guidance parse (present/absent/with-issues) + outcomes classification (greenlit/declined/pending); check-sync green. Live against porksicle: outcomes flow in, and with no proposal history yet the model correctly emits zero guidance — the "only on real signal" restraint holds.

That's the CEO layer at 100% (digest → proposals → self-refining mandate).

## CEO Phase 3 — decision-guidance redlines (the layer's 100%) The mandate-as-living-board-document, fully realized: **the CEO drafts mandate edits, the board ratifies by merging.** No board member files their own mandate edits. **How it works:** - The weekly pass gathers **the board's verdicts on its prior proposals** — greenlit (`Agent`-labeled) / declined (closed) / pending (`ceo_proposal_outcomes`) — and folds them into the prompt. - When those reveal a **clear, durable pattern**, the model ends its response with a `===GUIDANCE===` line (parsed into `.guidance`). No signal → nothing. - The harness **opens a PR** appending that entry to a `## Decision guidance` section in `CEO.md` (`ceo_open_guidance_pr` — contents-API + `new_branch`, no clone), assigned to you to merge. Over weeks, `CEO.md` accumulates "how Josh actually decides," the CEO reads its own mandate, and asks less. **Safety posture (unchanged):** - **Append-only** — it adds what it learned, never rewrites or erases existing guidance. A bad entry is at worst a bullet you decline. - **Throttled** to one open guidance PR (`ceo_guidance_pr_open`) — redlines never stack. - The CEO **still never commits to `master` or merges** — it drafts (issues + redline PRs), the board ratifies. Same "propose, you ratify" line as Phase 2. **Validated:** unit tests for the guidance parse (present/absent/with-issues) + outcomes classification (greenlit/declined/pending); `check-sync` green. Live against porksicle: outcomes flow in, and with no proposal history yet the model correctly emits **zero** guidance — the "only on real signal" restraint holds. That's the CEO layer at 100% (digest → proposals → self-refining mandate).
feat(ceo): Phase 3 -- decision-guidance redlines (CEO drafts, board ratifies)
All checks were successful
Lint / check-sync (pull_request) Successful in 4s
Lint / check-sync (push) Successful in 4s
d79d93fb72
The weekly pass now learns how the board decides and proposes mandate edits --
the CEO drafts, Josh ratifies by merging, completing the mandate-as-living-doc
model.

- ceo_proposal_outcomes: gathers the board's verdicts on prior CEO proposals
  (greenlit = Agent-labeled / declined = closed / pending) -- the revealed-
  decision signal, folded into the weekly prompt.
- directive + ceo_parse_response: the call may end with a ===GUIDANCE=== line
  (parsed into .guidance) when the verdicts reveal a clear, durable pattern --
  only on real signal, else nothing.
- ceo_open_guidance_pr: appends the entry to a '## Decision guidance' section in
  CEO.md and opens a PR for the board to merge -- contents-API + new_branch (no
  clone). APPEND-ONLY (adds what it learned, never rewrites/erases); throttled
  to one open guidance PR (ceo_guidance_pr_open) so redlines never stack. The
  CEO still never commits to master -- it drafts, the board ratifies.
- tests: guidance parse (present/absent/with-issues) + outcomes classification.

Validated live: outcomes flow in; with no proposal history yet the model
correctly emits zero guidance (the restraint holds). bash -n + check-sync green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011KXPafSYJPY6XkWHHk1Lfs
Merge remote-tracking branch 'origin/master' into feat/ceo-mandate-redline
All checks were successful
Lint / check-sync (push) Successful in 4s
Lint / check-sync (pull_request) Successful in 4s
1ea7bf64c5
Author
Collaborator

🤖 Review — REQUEST_CHANGES (automated)

CI for 1ea7bf64: success

Summary: Adds CEO "Phase 3" decision-guidance redlines — parses an optional ===GUIDANCE=== section, classifies board verdicts on prior proposals (ceo_proposal_outcomes), and opens a throttled append-only PR to CEO.md (ceo_open_guidance_pr / ceo_guidance_pr_open). Scope is tight (~130 lines), no CI-config or workflow changes, no security concerns, CI is green, and the checklist matches the diff. The blocker is test coverage on the feature's riskiest, entirely-unverified code path.

Blocking

  • ceo_open_guidance_pr (lib/ceo.sh) is the most complex new function and is verified by nothing. It does a base64 decode → conditional ## Decision guidance section creation → bullet append → base64 re-encode → contents PUT → PR open. None of that is unit-tested, and by the PR's own account it was not exercised live either ("with no proposal history yet the model correctly emits zero guidance" — so the if [ -n "$guidance" ] branch never fired against porksicle). That's the worst combination: the core PR-opening mechanics have never actually run. The harness already supports exactly this kind of test — ceo_file_proposal is tested by capturing the POST body (POST_BODY) and asserting on it. Please add an equivalent: mock _fj to return a known CEO.md, invoke ceo_open_guidance_pr, and assert the captured PUT body's decoded content contains (a) the new ## Decision guidance header when absent, and (b) the - <week>: <guidance> bullet. A test for ceo_guidance_pr_open (head-ref ceo-guidance* → throttles) would close the loop too.

Non-blocking observations

  • Same-week branch collision: branch="ceo-guidance-${week}" is derived from date +%G-W%V, so it's stable for the whole ISO week. If a guidance PR is merged early in the week and its branch isn't deleted, a second guidance attempt that same week will fail the new_branch PUT and only log a warning. The open-PR throttle doesn't cover the merged-but-undeleted case. Likely rare given the weekly cadence, but worth a comment or a uniquifier.
  • Append placement: the new bullet is appended to the end of the file, not to the end of the ## Decision guidance section. This is correct only as long as that section stays last in CEO.md. If anything is ever added below it, bullets land under the wrong heading. Fine for the current design; just fragile to document.

What's good

  • Parse logic (ceo_parse_response) correctly splits ===GUIDANCE=== before body/issues, and the three parse tests (absent / present / coexists-with-issue) plus the verdict-classification tests (greenlit / declined / pending / ignores-non-proposals) are solid and on-point.
  • Throttling logic and the "never commits to master / board ratifies by merging" posture are consistent with the description; guidance/FORGEJO_REVIEWER gating is sensible.
  • jq --arg / printf %s usage keeps model-supplied guidance out of any injection surface.

Add the ceo_open_guidance_pr test (the one path that is neither unit-tested nor was run live) and this is in good shape.


Independent review by the harness on claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.

### 🤖 Review — `REQUEST_CHANGES` _(automated)_ CI for `1ea7bf64`: **success** **Summary:** Adds CEO "Phase 3" decision-guidance redlines — parses an optional `===GUIDANCE===` section, classifies board verdicts on prior proposals (`ceo_proposal_outcomes`), and opens a throttled append-only PR to `CEO.md` (`ceo_open_guidance_pr` / `ceo_guidance_pr_open`). Scope is tight (~130 lines), no CI-config or workflow changes, no security concerns, CI is green, and the checklist matches the diff. The blocker is test coverage on the feature's riskiest, entirely-unverified code path. **Blocking** - **`ceo_open_guidance_pr` (lib/ceo.sh) is the most complex new function and is verified by *nothing*.** It does a base64 decode → conditional `## Decision guidance` section creation → bullet append → base64 re-encode → contents PUT → PR open. None of that is unit-tested, and by the PR's own account it was *not* exercised live either ("with no proposal history yet the model correctly emits **zero** guidance" — so the `if [ -n "$guidance" ]` branch never fired against porksicle). That's the worst combination: the core PR-opening mechanics have never actually run. The harness already supports exactly this kind of test — `ceo_file_proposal` is tested by capturing the POST body (`POST_BODY`) and asserting on it. Please add an equivalent: mock `_fj` to return a known CEO.md, invoke `ceo_open_guidance_pr`, and assert the captured PUT body's decoded `content` contains (a) the new `## Decision guidance` header when absent, and (b) the `- <week>: <guidance>` bullet. A test for `ceo_guidance_pr_open` (head-ref `ceo-guidance*` → throttles) would close the loop too. **Non-blocking observations** - **Same-week branch collision:** `branch="ceo-guidance-${week}"` is derived from `date +%G-W%V`, so it's stable for the whole ISO week. If a guidance PR is merged early in the week and its branch isn't deleted, a second guidance attempt that same week will fail the `new_branch` PUT and only log a warning. The open-PR throttle doesn't cover the merged-but-undeleted case. Likely rare given the weekly cadence, but worth a comment or a uniquifier. - **Append placement:** the new bullet is appended to the *end of the file*, not to the end of the `## Decision guidance` section. This is correct only as long as that section stays last in `CEO.md`. If anything is ever added below it, bullets land under the wrong heading. Fine for the current design; just fragile to document. **What's good** - Parse logic (`ceo_parse_response`) correctly splits `===GUIDANCE===` before body/issues, and the three parse tests (absent / present / coexists-with-issue) plus the verdict-classification tests (greenlit / declined / pending / ignores-non-proposals) are solid and on-point. - Throttling logic and the "never commits to master / board ratifies by merging" posture are consistent with the description; `guidance`/`FORGEJO_REVIEWER` gating is sensible. - `jq --arg` / `printf %s` usage keeps model-supplied guidance out of any injection surface. Add the `ceo_open_guidance_pr` test (the one path that is neither unit-tested nor was run live) and this is in good shape. --- <sub>Independent review by the harness on `claude-opus-4-8`. The human reviewer is requested once Igor has reviewed; a human still merges.</sub> <!-- review sha=1ea7bf64c5ca286d4c8fcb8a515f2b6346bf9e0a verdict=REQUEST_CHANGES ci=success -->
igor added spent time 2026-06-25 19:32:37 +00:00
1 minute 48 seconds
igor self-assigned this 2026-06-25 19:32:38 +00:00
joshtronic approved these changes 2026-06-25 19:34:42 +00:00
joshtronic deleted branch feat/ceo-mandate-redline 2026-06-25 19:34:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
2 participants
Notifications
Total time spent: 1 minute 48 seconds
igor
1 minute 48 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
joshtronic/igor!250
No description provided.