feat(ceo): Phase 4 follow-up -- conversational proposals + two-way on proposals + metrics hardening #286
No reviewers
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
2 participants
Notifications
Total time spent: 3 minutes 38 seconds
Due date
igor
3 minutes 38 seconds
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor!286
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/ceo-phase4-followup"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
CEO Phase 4 follow-up — three fixes the CEO's first live porksicle cycle surfaced (#100/#101).
1. Conversational bodies (directive). The first proposals read like dry feature tickets. The directive now has the CEO open each proposal/question body with its read — what in the numbers/week put it on the desk, the strategic why, the call it's making, in its own voice — then scope/acceptance. Reasoning first, spec second.
2. Two-way on proposals (the real catch). You commented on proposal #101 and unassigned yourself — the same "act on this" gesture the question channel uses — but Path 1 only read question comments, so your feedback would have sat unread. New Path 1b: when the reviewer comments on a
ceo-proposaland unassigns without theAgentlabel, the CEO reconsiders it:It does not do the proposed work (that stays the
Agent-label → grind path). Detection requires unassigned + not Agent-labeled + has a comment, so a greenlight never trips it. One reconsider per tick (after answered-questions); every branch (incl. unparseable) closes or re-assigns so there's no per-tick reconsider loop; a REVISE re-file respectsCEO_MAX_OPEN.3. Metrics-fetch hardening (from PR 2's shadow review):
ceo_read_metricsnow requireshttps://(blocksfile://,http://-internal, cloud-metadata) and caps the body (head -c 65536) — an oversize/hostile response truncates past valid JSON and degrades to the existing "unavailable" path.New:
ceo_responded_proposal_numbers,ceo_proposal_thread,ceo_build_reconsider_prompt,ceo_parse_reconsider. Tests cover the reconsider parse (incl. failure modes), the detection, and both hardening guards.Verified:
bash -n+bin/test-ceo.sh(all pass) + check-sync green. Note: built foreground — a fork/API glitch ate two delegated attempts, so I wrote and reviewed it directly (incl. catching + fixing the HOLD-reconsider loop myself before commit). No reviewer.🤖 Review —
COMMENT(automated)CI for
d4dcb5ae: successSummary: Adds three CEO Phase-4 follow-ups — conversational proposal/question bodies (directive prose), a new "Path 1b" that reconsiders a proposal the board commented on + handed back (WITHDRAW/REVISE/HOLD), and https-only + size-cap hardening on the metrics fetch. CI is green, the diff is ~200 lines, and the description maps honestly to the diff. My one reason for not approving outright: the new tick.sh state machine (which closes and re-files live issues) has no direct test, and this was a self-built, unreviewed change — I want a human to eyeball the orchestration.
Findings
bin/tick.shPath 1b (~L1902-1950) — untested orchestration on a live mutation path. The loop-prevention reasoning traces correctly to me: WITHDRAW/REVISE bothPATCH state:closed(drops out of thestate=openquery), and HOLD re-assigns the reviewer (drops out of theindex($r) | notfilter inceo_responded_proposal_numbers). So no per-tick reconsider loop, as claimed. But the only tests are on the helpers (ceo_parse_reconsider,ceo_responded_proposal_numbers) — the close/re-file/re-assign flow itself is exercised by nothing. Given it closes and re-files real issues, a human should confirm this path before it runs live.bin/tick.sh—prompt,raw,attemptare not declaredlocal. Thelocalline only listsresponded rnum rparsed rdecision rreply rissue. It's harmless today (every branch hitsreturn 0), but these leak into the enclosing scope and are a foot-gun for future edits; add them to thelocaldeclaration.bin/tick.shREVISE-at-cap (~L1932-1940) — proposal silently dropped. Whenceo_open_items_count >= CEO_MAX_OPEN, the old proposal is closed with a "tightening scope" reply comment, but no revision is re-filed. The board sees a closed issue promising a revision that never appears (it's logged, but not surfaced to the reviewer). Minor UX wrinkle, not a blocker.lib/ceo.shceo_read_metrics) is a separate, orthogonal security fix ("from PR 2's shadow review") bundled with the proposal-reconsider feature. Mild scope creep — defensible as one "follow-up," but it's not the same concern as #1/#2._ceo_trim_blanks,_ceo_parse_issues,ceo_file_proposal,ceo_open_items_count,claude_call,_fj,CEO_PROPOSAL_MARKER,CEO_MAX_OPEN,forgejo_assignare all pre-existing and not shown; green CI + the new unit tests give reasonable confidence they behave.Positives
https://*allowlist blocksfile:///http://-internal/cloud-metadata, andhead -c 65536caps a hostile/oversize body so it degrades to the existing "unavailable" path. Both guards are tested.ceo_parse_reconsiderkeeps JSON harness-built (never model-written), validates DECISION + ===REPLY===, and has failure-mode tests (missing decision, missing sentinel, whitespace-only reply).Recommendation: Have a human confirm the Path 1b live-mutation flow and decide whether the REVISE-at-cap silent-drop is acceptable; consider adding the missing
locals. Nothing here clearly blocks, but the untested issue-closing/re-filing logic on an unreviewed change is worth a human glance before merge.Independent review by the harness on
claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.d4dcb5ae353d6b2f6cf6🤖 Review —
COMMENT(automated)CI for
3d6b2f6c: successSummary: CEO Phase 4 follow-up — directive tweaks for conversational proposal bodies, a new "reconsider a handed-back proposal" path (Path 1b in
tick.sh+ four helpers inlib/ceo.sh), and SSRF/size hardening of the metrics fetch. CI is green, scope is coherent, and the description's claims all map to real diff. No blocking defect, but a couple of reservations I'd want a human to weigh before merge.Checklist / honesty check (all verified):
bin/lib/ceo-digest-directive.md. ✓bin/tick.sh; helpersceo_responded_proposal_numbers,ceo_proposal_thread,ceo_build_reconsider_prompt,ceo_parse_reconsiderall present inlib/ceo.sh. ✓head -c 65536) — present inceo_read_metrics. ✓bin/test-ceo.sh. ✓Positives:
ceo_read_metricshardening is genuinely good defense: thehttps://*case-guard blocksfile:///http://-internal/metadata, and sincecurlhas no-Lit won't follow a redirect into those either. The size cap degrades cleanly to the existing "unavailable" path (tested).state=open/unassigned filtering, so it can't reconsider-loop. The detection (unassigned + not Agent-labeled + comments>0) correctly avoids tripping on freshly-filed (still-assigned) or greenlit (Agent-labeled) proposals; the 5-case detection test confirms each exclusion.Reservations (none blocking, but worth a human glance):
bin/tick.sh, thecaseblock): both paths post a comment thenPATCH ... "closed"with|| true, relying on the close to drop the issue out of thestate=openset. If the close API call persistently fails (perms, etc.), the issue stays open + unassigned + now has the CEO's reply comment → it re-enters the responded-set next tick and gets re-withdrawn, spamming a new comment each tick. The HOLD/unparseable paths were deliberately guarded against this via re-assign; WITHDRAW/REVISE were not. Transient failures self-heal, so this is an edge case — but it's the one spot where the "no per-tick reconsider loop" guarantee in the description isn't actually enforced.ceo_parse_reconsiderfailure modes), but the Path 1b branching itself — the WITHDRAW/REVISE/HOLD dispatch, the re-fileCEO_MAX_OPENgate, the close-then-count ordering — has no test. That's the most state-mutating, error-prone part of the change. It reads correctly on inspection (close happens before theceo_open_items_countcheck, so the freed slot is counted; comment posts before the case), but I'm verifying by eye, not by test.prompt,raw,attemptin the Path 1b block are not in thelocaldeclaration (local responded rnum rparsed rdecision rreply rissue). Likely benign reuse of locals already declared earlier indo_ceo_tick, but worth confirming they don't leak.Couldn't verify from the diff:
_ceo_parse_issues,_ceo_trim_blanks,ceo_file_proposal,forgejo_assign,claude_callsignature, and theCEO_PROPOSAL_MARKER/CEO_MAX_OPEN/FORGEJO_REVIEWERdefinitions all live outside this diff; I'm assuming existing behavior. The PR also notes it was built foreground with no reviewer, which is the main reason I'm routing this to a human rather than approving.Independent review by the harness on
claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.