Skip to content

feat(B-0400): bus-gate integration — allActiveClaims + --with-bus-claims (slice 5)#2959

Merged
AceHack merged 3 commits into
mainfrom
feat/b-0400-slice5-bus-gate-integration
May 13, 2026
Merged

feat(B-0400): bus-gate integration — allActiveClaims + --with-bus-claims (slice 5)#2959
AceHack merged 3 commits into
mainfrom
feat/b-0400-slice5-bus-gate-integration

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 13, 2026

Summary

  • claim.ts: export allActiveClaims() — collects active claims across all backlog items by discovering unique itemIds from claim-topic messages, then delegating per-item to activeClaims() for correct claim/release semantics
  • poll-pr-gate-batch.ts: --with-bus-claims flag appends active bus claims (busClaims?: ClaimRecord[]) to the BatchReport JSON, giving the autonomous loop PR-gate state + bus coordination state in one call
  • DST-clean injection: BusClaimsFn injectable type + pollFn injection in main() — tests never spawn gh or touch the filesystem

Slice context

Slices 1–4 shipped (types + CLI + watch + claim-coordinator + status subcommand). This is slice 5: the poll-pr-gate-batch.ts integration listed as deferred in the backlog item.

Usage after this slice:

bun tools/github/poll-pr-gate-batch.ts --with-bus-claims 2944 2953
# BatchReport now includes busClaims: [{ from: "otto", itemId: "B-0400", branch: "...", ... }]

Test results

bun test tools/bus/           → 64 pass, 0 fail   (+3 new allActiveClaims tests)
bun test tools/github/poll-pr-gate-batch.test.ts → 14 pass, 0 fail   (+4 new main() tests)
dotnet build -c Release       → 0 warnings, 0 errors
bunx tsc --noEmit             → 0 errors in changed files

Checklist

  • Rule 0: TypeScript only
  • Build gate: dotnet build -c Release → 0 warn / 0 err
  • Tests: 78 total pass, 0 fail
  • Bus claim acquired before work: claim.ts acquire --from otto --item B-0400
  • Backlog item updated with slice 5 scope
  • operative-authorization: aaron 2026-05-13: "cooling periods, harsh-critic reviewers, F# anchor sanity check"

🤖 Generated with Claude Code

…ims (slice 5)

- claim.ts: export allActiveClaims() — collects active claims across all
  backlog items by discovering unique itemIds from claim-topic messages
  and delegating per-item to activeClaims() for correct release semantics
- poll-pr-gate-batch.ts: --with-bus-claims flag appends active bus claims
  to the BatchReport output (busClaims?: ClaimRecord[])
- BusClaimsFn injectable type + pollFn injection in main() for full DST
  coverage without gh subprocess in tests
- 3 new tests in claim.test.ts (allActiveClaims across items, with release)
- 4 new tests in poll-pr-gate-batch.test.ts (flag present/absent, empty list)
- bun test tools/bus/ → 64 pass; bun test poll-pr-gate-batch.test.ts → 14 pass
- dotnet build -c Release → 0 warnings, 0 errors

operative-authorization: aaron 2026-05-13: "cooling periods, harsh-critic reviewers, F# anchor sanity check"

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 13, 2026 06:52
@AceHack AceHack enabled auto-merge (squash) May 13, 2026 06:52
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57c0c7430c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/bus/claim.ts Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds bus-claim visibility to the PR gate batch poller so callers can retrieve PR gate state and cross-agent coordination state in a single JSON payload, aligned with B-0400 slice 5.

Changes:

  • Export allActiveClaims() from tools/bus/claim.ts to aggregate active claims across all backlog items.
  • Add --with-bus-claims to poll-pr-gate-batch.ts, appending busClaims to the BatchReport output (with injectable BusClaimsFn for deterministic tests).
  • Extend unit tests for both allActiveClaims() and main()/--with-bus-claims, and update the B-0400 backlog slice notes.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/github/poll-pr-gate-batch.ts Adds --with-bus-claims output and injectable BusClaimsFn/pollFn to keep tests deterministic.
tools/github/poll-pr-gate-batch.test.ts Adds main() coverage for --with-bus-claims and stdout capture.
tools/bus/claim.ts Adds allActiveClaims() to aggregate active claims across items.
tools/bus/claim.test.ts Adds tests validating allActiveClaims() behavior across multiple items and releases.
docs/backlog/P1/B-0400-inter-agent-ephemeral-communication-bus-nats-protocol.md Documents slice 5 scope/details for the integration.

Comment thread tools/bus/claim.ts Outdated
Comment thread tools/github/poll-pr-gate-batch.test.ts Outdated
Comment thread docs/backlog/P1/B-0400-inter-agent-ephemeral-communication-bus-nats-protocol.md Outdated
AceHack and others added 2 commits May 13, 2026 03:00
…ctiveClaims, test rename, doc count

Three Codex/Copilot review findings resolved:

1. perf(claim.ts): refactor allActiveClaims() from O(items×messages) to single-pass.
   Previously: list() once to discover item IDs, then activeClaims(id) per item
   (each calling list() again). Now: one list() call, groupBy (from:itemId) in
   a single pass — identical tiebreaker logic to activeClaims().

2. test(poll-pr-gate-batch): rename misleading test — was 'empty-PR early-return
   path' but actually tests 'busClaimsFn returns empty list'. Updated comment to
   clarify that --all-open empty path requires injectable listOpenPRs (not done here).

3. docs(B-0400): correct test count 4→3 in slice-5 scope section.

All 33 claim tests + 14 poll-pr-gate-batch tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>
grok-4.3 collapses thinking/fast into one model identifier; the Mode
parameter is preserved for future cursor-agent updates but is currently
unread, causing TS6133 under noUnusedLocals.

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 13, 2026 07:07
@AceHack AceHack merged commit 7c622df into main May 13, 2026
29 of 30 checks passed
@AceHack AceHack deleted the feat/b-0400-slice5-bus-gate-integration branch May 13, 2026 07:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread tools/bus/claim.ts
timestamp: m.timestamp,
expiresAt: m.expiresAt,
});
}
AceHack added a commit that referenced this pull request May 13, 2026
…nfirmation 2026-05-13 (#3035)

Aaron 2026-05-13 activated Otto on Claude Desktop alongside Otto-CLI,
running the multi-foreground-surface architecture from PR #3030 for
the first time. Preserves operational discoveries:

1. Claude Desktop Routines are GIT-TRACKED (durable across sessions)
   vs Claude Code CronCreate session-only — supersedes 'every session
   MUST CronList' mechanism at Desktop scope

2. Two cadence layers in Desktop: Loop (minute, session-bounded) +
   Routine (configurable, git-tracked). Both fire simultaneously.

3. CRITICAL ARCHITECTURAL GAP: SENDER_IDS in tools/bus/types.ts
   doesn't distinguish multi-surface instances. claim.ts treats
   --from otto from CLI and Desktop as IDENTICAL — split-brain
   prevention fails without schema extension. Vera caught this on
   PR #3032 review. Workarounds: lane-based + branch-prefix +
   future schema extension.

4. Approval friction profile shapes lane split natively:
   - Otto-CLI: better at .claude/rules/ edits (auto-accept covers)
   - Otto-Desktop: better at substrate + conversation + routines
   - The lane split emerges from approval costs, not convention —
     more robust because friction enforces it

Generalizable principle: multi-foreground-surface works because
surfaces have DIFFERENT cost profiles, not because they're redundant
clones. Future multi-instance work should match work to lowest-
friction surface for that work shape.

Composes with:
- Otto canonical bootstream (full canonical + tight)
- .claude/rules/tick-must-never-stop.md (CLI cron caveat)
- .claude/rules/claim-acquire-before-worktree-work.md (the rule
  with the architectural gap named)
- .claude/rules/holding-without-named-dependency-is-standing-by-failure.md
- B-0400 slice 3 (PR #2939) + slice 5 (PR #2959)
- fetch-before-push memory (sibling discipline at git scope)

Co-authored-by: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 13, 2026
…on for multi-Otto) (#3032)

* docs(rules): claim acquire before worktree-creating backlog work (split-brain prevention for multi-Otto)

Aaron 2026-05-13 set up Otto on Claude Desktop alongside Otto-CLI,
creating a real multi-foreground-surface split-brain risk. Both Ottos
share git + bus on one machine and could pick the same backlog row
simultaneously.

The claim-coordinator (tools/bus/claim.ts, B-0400 slice 3) was built
for this — atomic check/acquire/release with PID-liveness + 24h TTL.
PR #2939 shipped it; PR #2959 added the gate integration. The
infrastructure exists; this rule is the discipline-level mechanization
that auto-loads at cold-boot so both Ottos read it + use it before
worktree-creating backlog work.

Applies to: starting work on a B-NNNN row, creating feature branch +
worktree, opening a backlog-advancing PR.

Does NOT apply to: CI fixes on already-claimed PRs, ad-hoc memory-
file writes, conversation-driven substrate, hot fixes.

Composes with:
- backlog-item-start-gate.md (this rule adds zero-th step)
- dont-ask-permission.md (acquire exit 0 IS the substrate permission)
- never-be-idle.md (if acquire fails, pick another row)
- B-0400 + slice 3 + slice 5 infrastructure
- Otto Claude Desktop bootstream (PR #3030)
- fetch-before-push memory (sibling coordination pattern at git scope)

Future substrate-level mechanization: pre-commit hook that auto-calls
'claim check' and fails on no-held-claim. Today's rule is the
discipline-level fix.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(rules): correct Example 2 — multi-surface Otto can't be distinguished by same --from value (Vera P1)

Vera caught (PR #3032 review): the original Example 2 showed two Ottos
calling 'acquire --from otto' and the second exiting 1. That's WRONG
per claim.ts line ~270 — same --from is filtered out as self-re-
acquire (idempotent). Both calls succeed; split-brain not prevented.

Fix:
- Example 2 renamed to "KNOWN GAP" — shows actual behavior (both
  succeed) + names the architectural cause (SENDER_IDS doesn't
  distinguish multi-surface instances)
- Added workarounds: lane-based convention, branch-prefix discipline,
  schema extension (otto-cli / otto-desktop)
- New Example 3 shows TARGET behavior with schema fix (--from otto-cli
  vs --from otto-desktop)
- Example 3 renamed to Example 4 (crash recovery)

The architectural gap is a real follow-up: extending SENDER_IDS to
support multi-surface instances of the same logical agent. Future
work, not this PR.

Operational consequence today: use the lane-based + branch-prefix
workarounds. Claim-coordinator is INSUFFICIENT for multi-Otto without
the schema extension.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(rules): fix false split-brain + PID-liveness claims

P1 (PRRT_kwDOSF9kNM6B5VwU): carved sentence claimed split-brain
is  but claim.ts filters by c.from !== sender, soprevented
same-sender instances both exit 0. Updated to state --from must
differ and document the known gap explicitly.

P2 (PRRT_kwDOSF9kNM6B5VwX): example 4 claimed PID-liveness can
reclaim a claim mid- no such mechanism exists. Only TTLTTL
expiry or explicit release ends a claim. Corrected comment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(rules): remove branch-prefix as split-brain workaround (Vera P2 caught it doesn't work)

Vera caught: branch-prefix doesn't prevent split-brain because
claim.ts only filters by 'from', not by 'branch'. Two Ottos with
same --from otto but different --branch both succeed (both exit 0).
The branch field is post-hoc metadata, not a coordination key.

Real workarounds reduce to:
1. Lane-based convention (zero-code; ONLY real prevention today)
2. Schema extension (future SENDER_IDS additions)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(rules): carved sentence consistency — remove branch-prefix from workarounds (Vera P2)

The body of the rule was already corrected (commit 030513f) to remove
branch-prefix as a workaround. The carved sentence wasn't updated.
Vera caught the inconsistency.

Now carved sentence + body both say: lane-based convention is the
ONLY real split-brain workaround today.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

2 participants