feat(branch-trail): Layer 1 emit primitive for §9.4 CHIT trail - #1437
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughIntroduces branch lifecycle trail events for NATS publication. New ChangesBranch Trail Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9fabc92342
ℹ️ 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".
Canonical Python module + 36 unit tests for AGNOTE4482 §9.4 — the last
unchecked §9 hardening signoff item. Implements the emit primitive that
all other layers (CLI wrapper, HTTP gateway, GH Actions workflow) will
wrap.
## Module: pmoves/services/common/branch_trail.py
Public API:
- `emit(branch, event, agent_id, ...)` — async one-shot publish to
`branch.<path-segments>.trail.v1` via the W6-hoisted publish_cgp().
- `build_payload(...)` — produce the signed payload without publishing
(used by HTTP gateway, tests, dry-run inspection).
- `build_branch_event(...)` — produce just the branch_event sub-object.
- `encode_subject(branch)` — public utility for consumers building
wildcard subscriptions like `branch.feat.>.trail.v1`.
Module composes existing infrastructure with zero changes:
- pmoves.tools.sign_trail.build_payload → identity skeleton
- pmoves.tools.chit_security.sign_cgp → HMAC-SHA256 signing
- pmoves.services.common.nats_client.publish_cgp → NATS publish
## Subject pattern
Slashes in branch names map to NATS dot-tokens:
feat/w6-bpm-nats → branch.feat.w6-bpm-nats.trail.v1
This enables wildcard subscriptions (`branch.feat.>.trail.v1`) that are
otherwise impossible with literal slashes. Subject is not lossless when
branches contain `.` — consumers MUST use payload `branch_event.branch_name`
for the canonical name (test documents this).
## Auth
Per existing PMOVES convention:
- `CHIT_SIGNING_KEY` (preferred) or `CHIT_PASSPHRASE` (legacy fallback)
for HMAC keying. Function-level `passphrase=...` overrides env.
- `NATS_URL` for the bus address; function-level override available.
- Unsigned emit logs a warning but still publishes (best-effort
semantics — a missing trail entry must not block the operation that
triggered it).
## Tests: 36 passing
- encode_subject: 13 cases (slash mapping, dashes/underscores, max
length, NATS-special-char rejection, empty-string rejection).
- build_branch_event: 9 cases (event enum, ecosystem enum, fail-fast
on invalid branch, all 4 event types).
- build_payload: 6 cases (unsigned warns, env signing, env legacy
passphrase, param-overrides-env, summary format, sig structure).
- emit: 5 cases (subject + payload via mocked publish_cgp, failure path,
nats_url override, fail-fast on invalid branch/event).
- subject roundtrip: 3 cases (wildcard ergonomics, segment count,
documented non-lossless behavior with dotted branch names).
```
pytest pmoves/tests/services/common/test_branch_trail.py -v
36 passed in 0.60s
```
## Lane
§9.4 design-locked 2026-05-08 (plan + memory `project_branch_trail_94_design`).
Layer 1 of 4: this PR. Layers 2 (CLI), 3 (HTTP gateway), and the GH
Actions workflow consumer ship in follow-up PRs once Layer 1 is on main.
Spec amendments to `AGNOTE4482_SIGNOFF_CHECKLIST.md:89` and
`AGNOTE4482_ROADMAP_W1-W5.md:523` (subject-pattern from
`branch.{branch_name}` → `branch.<path-segments>`) ship with the
final close-out PR after E2E validates.
Co-authored-by: DARKXSIDE <cataclysmstudios@gmail.com>
9fabc92 to
ab5992b
Compare
|
Refresh after #1433/#1435 landed:
Local validation: |
|
5090 Codex refresh after CI follow-up:
Local validation:
Remote validation on head
|
POWERFULMOVES
left a comment
There was a problem hiding this comment.
Branch refreshed after #1439 so the required CHIT verify check exists on this PR head. Local verification from this node: .venv\Scripts\python.exe -m pytest pmoves/tests/services/common/test_branch_trail.py -v → 46 passed in 0.64s. Current remaining gate is fresh write-access approval because the refresh commit made the prior approval stale.
* feat(branch-trail): §9.4 Layer 4 workflow + spec amendment
Closes the last unchecked AGNOTE4482 §9 hardening item by wiring
branch lifecycle events through to the NATS CHIT trail.
Adds:
- .github/workflows/branch-trail-emit.yml — push/pull_request/delete
triggers on a [self-hosted, ai-lab] runner, best-effort emit.
- .github/scripts/branch_trail_ci.py — pure event-parser shim that
maps GitHub event payloads onto the Layer 1 emit() primitive.
- pmoves-ci-bot signing card (0035) for HMAC-signed CI emissions.
- 15 unit tests on the shim's parse_github_event() — green locally.
Amends the spec subject pattern from `branch.{branch_name}.trail.v1`
to `branch.<path-segments>.trail.v1` (slash→dot encoding) in:
- AGNOTE4482_SIGNOFF_CHECKLIST.md:89
- AGNOTE4482_ROADMAP_W1-W5.md:523
- stale-branch-sweep.yml:67 (comment only)
Builds directly on PR #1437 (Layer 1 emit primitive, merged 2026-05-11).
Defers Layer 2 (CLI wrapper) and Layer 3 (HTTP gateway) until a
non-tailnet emitter actually needs them — keeps the close-out PR small.
§9.4 checkbox flip deferred to a follow-up after live E2E proves all
four events (create / link_pr / merge / delete) arrive on the bus.
Co-Authored-By: DARKXSIDE <cataclysmstudios@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(branch-trail): wire existing CHIT pass-secret into emit workflow
The existing CHIT pass-secret has been in the repo since 2026-02-27.
L1's emit() already falls back through the env-var chain at line 173
of pmoves/services/common/branch_trail.py. Wiring this existing repo
secret directly into the workflow env means the operator only has to
set the new NATS_URL_TAILNET secret — signing works out of the gate
without generating fresh key material.
The CHIT_SIGNING_KEY env stays in the block for the future split-key
rollout (advisory mode per Owner-Decision D).
Co-Authored-By: DARKXSIDE <cataclysmstudios@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(agnote): add W0 follow-on REVIEW-REQUEST entry (issue #1463)
Captures the operator-observed drift root cause surfaced during the
§9.4 close-out: NATS host-bind + GH Actions runner registration +
mesh-bind override autogen all share the same hand-rolled-per-node
provenance. Three atomic PRs proposed in #1463 for review by
4090-CLAUDE / Z890-CLAUDE / CODEX-GPT5 / operator DARKXSIDE.
Not a claim — review/discussion only.
Co-Authored-By: DARKXSIDE <cataclysmstudios@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(agnote): add network-hardening REVIEW-REQUEST entry (issue #1465)
Sibling lane to #1463 — repo has 11 service-tier hardening anchors
but zero network-tier anchors for the 6 docker networks. Four atomic
PRs proposed in #1465. Sequences before #1463 PR-A (mesh-bind
auto-write) — the audit feeds the doctrine which feeds bootstrap.
Reviewers: Z890-CLAUDE, 4090-CLAUDE, CODEX-GPT5, operator DARKXSIDE.
Co-Authored-By: DARKXSIDE <cataclysmstudios@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* debug(branch-trail): structural fingerprint of NATS URL secret for E2E debug
* chore(branch-trail): remove diagnostic step after E2E verification
E2E proof landed live on NATS — HMAC-signed payload received from
GH Actions emit on pmoves-ai-lab-runner. Diagnostic served its
purpose finding the gh secret set syntax bug (--body - was treating
- as literal value, not stdin indicator).
* docs(agnote): §9.4 RELEASE — acceptance criterion satisfied in production
Workflow emit ran end-to-end on revived pmoves-ai-lab-runner.
HMAC-signed payload landed on NATS with signing_card_id 0035 and
real GH event metadata (committer, sha, runner). Follow-up: §9.4
checkbox flip after delete event proves on main.
Co-Authored-By: DARKXSIDE <cataclysmstudios@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(branch-trail): harden CI workflow — fork RCE guard + create event + best-effort wraps
Addresses 6 CodeRabbit threads on PR #1462:
- [T7 Critical] Add fork guard to emit job: prevents fork PRs from running
on the tailnet-connected self-hosted runner (RCE via pull_request event)
- [T1 P1] Add `create` trigger + parse_github_event handler: branches created
via GitHub UI/API now emit trail entries without a first push
- [T2 Major] Wrap _load_event_payload() and emit() in try/except: keeps the
stated best-effort/exit-0 contract even on unexpected raises
- [T4 Critical] Add pmoves-ci-bot to agent_registry.yaml: signing card 0035
was present but the agent was missing from the canonical registry
- [T5/T6 Major] Add branch.<path-segments>.trail.v1 to nats-subjects.md:
documents the §9.4 subject pattern used by Layer 1 + Layer 4
- [T8] Diagnostic fingerprint step already removed (verified absent)
- [T3 False-positive] actionlint ai-lab label — not enforced in this repo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Shaela Bello <slbello@uncg.edu>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
First of four PRs implementing AGNOTE4482 §9.4 — the last unchecked §9 hardening signoff item: "CHIT trail is recorded for branch lifecycle events (creation, PR link, merge, deletion) on NATS subject
branch.<path-segments>.trail.v1."Design was locked 2026-05-08 (per memory
project_branch_trail_94_design). This PR ships Layer 1 — the canonical Python module that all higher layers (CLI, HTTP gateway, GH Actions workflow) wrap.Why this lane is unblocked now
§9.4 was blocked since 2026-04-25 per
AGNOTE4482PHI.t1.md:420: "§9.4 (blocked — CHIT trail wiring requires NATS bus)." The W6-bpm-NATS lane (PR #1425, merged 2026-05-08) hoistedpublish_cgp()intopmoves/services/common/nats_client.pyand proved the publish pattern. Layer 1 reuses that helper directly.What's in this PR
Public API
Subject encoding
Slashes in branch names map to NATS dot-tokens to enable wildcard subscriptions:
mainbranch.main.trail.v1feat/w6-bpm-natsbranch.feat.w6-bpm-nats.trail.v1chore/codex/paritybranch.chore.codex.parity.trail.v1Subscribers can filter by prefix:
branch.feat.>matches allfeat/*branches. Subject is not lossless when a branch name contains.— consumers MUST use payloadbranch_event.branch_namefor the canonical name (one test documents this explicitly).Reuses (zero changes to upstream code)
publish_cgp()async helperpmoves/services/common/nats_client.py:292-320(PR #1425)build_payload()identity skeletonpmoves/tools/sign_trail.py:154-211sign_cgp()HMAC-SHA256 signerpmoves/tools/chit_security.pyagent_signatures.yamllookupAuth
Same convention as existing CHIT signing:
CHIT_SIGNING_KEYpreferred,CHIT_PASSPHRASElegacy fallback. Function-levelpassphrase=...overrides env. Unsigned emit logs a warning but still publishes — best-effort semantics so a missing trail entry never blocks the operation that triggered it.Tests
Coverage:
encode_subject: 13 cases — slash mapping, dashes/underscores, max length, NATS-special-char rejection, empty rejectionbuild_branch_event: 9 cases — event enum, ecosystem enum, fail-fast on invalid branch, all 4 event typesbuild_payload: 6 cases — unsigned warns, env signing, env legacy passphrase, param-overrides-env, summary formatemit: 5 cases — subject + payload via mockedpublish_cgp, failure path,nats_urloverride, fail-fast on invalid branch/eventRoadmap
python -m pmoves.tools.branch_trail)/branch-trail/emitvia Tailscale Funnel)Lane
§9.4 design plan:
C:/Users/russe/.claude/plans/yes-and-status-of-silly-lemon.md(5090-CLAUDE local; will be committed to repo with the close-out PR).Memory pointer:
project_branch_trail_94_design.md.Spec amendments to
AGNOTE4482_SIGNOFF_CHECKLIST.md:89andAGNOTE4482_ROADMAP_W1-W5.md:523ship in the final close-out PR after E2E validates.Co-authored-by: DARKXSIDE cataclysmstudios@gmail.com
Summary by CodeRabbit
New Features
Improvements
Tests
Chores