Skip to content

feat(rooms): open-room lane — P7 runtime + schema extensions + catalog stage + A2UI consumer - #2173

Merged
POWERFULMOVES merged 18 commits into
mainfrom
feat/open-room-lane
Jul 25, 2026
Merged

feat(rooms): open-room lane — P7 runtime + schema extensions + catalog stage + A2UI consumer#2173
POWERFULMOVES merged 18 commits into
mainfrom
feat/open-room-lane

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the open-room lane: a single PR that takes the rooms-on-a-stage model from "declarative doc + stale prototype" to "working service + aligned docs + A2UI consumer + operator skill + slash commands." P7 (the room-aware stage manager) goes from a concept with 3 inconsistent definitions (rooms doc / approved spec / pre-existing p7-room-orchestrator with its own vocabulary) to one canonical implementation.

The work was originally in a feat-auto-* worktree with unrelated changes piled on; this PR cherry-picks just the 8 open-room lane commits onto a clean feat/open-room-lane branch off main.

What's in this PR

1. Schema + catalog + checklist (first slice, feat(rooms): ...)

  • Schema extensions to pmoves/contracts/schemas/room/room.manifest.v1.schema.json (additive, provisional per AGNOTE4482 §1348):
    • room_type enum gains "exchange" (for the ToKenism floor)
    • panels[].kind enum gains "browser" (for webview surfaces)
    • Top-level meta object added (free-form, additionalProperties: true) for inline CHIT signing-card references; the spec doc explicitly notes this is the interim path until a first-class chit_card field lands
  • catalog.json bumped to schema_version 1.2.0; every room row now carries current_stage (3 live / 5 rehearsal / 1 archive), stage_source, stage_verified_at — closes P7's fast-lookup gap
  • CHIT activation checklist consolidated to pmoves/docs/ROOM_MANIFEST_CONTRACT.md as the single canonical source (7 items, rehearsal → live vocabulary corrected from the historical planned → active). The other two copies (ROOMS_ON_A_STAGE.md, AGNOTE4482.md) now link out — historical audit trail in AGNOTE4482.md preserved with a forward-pointer note
  • suitsoverlays rename in both room docs to break the term collision with pmoves/configs/model-suits/ (per-model YAML profiles)
  • pmoves/config/rooms/tokenism.room.exchange.json skill_bindings now have all required fields (skill_id, room_id, context.sources, outputs, guardrails)

2. P7 runtime service (Option A — aligned the pre-existing p7-room-orchestrator, feat(p7): align ...)

The pre-existing 333-line pmoves/services/p7-room-orchestrator/app.py was an early prototype with a different vocabulary (planned/active/paused/ended/archived, chit.capability/handler/integration/trigger, NATS p7.room.session.*.v1, port 8092, no compose entry). Aligned it to the approved spec:

  • Split app.py into 5 modules:
    • config.py — Pydantic settings (P7_*-prefixed env vars)
    • catalog.pyCatalogLoader with atomic current_stage writeback (write-temp + rename) and schema-validated manifest loads (with skill.binding.v1.schema.json $ref resolution via referencing.Registry)
    • nats_pub.pyNATSPublisher with HMAC-SHA256 signing + log-only fallback when NATS is unreachable
    • transition.pyTransitionEngine with the canonical 7-item CHIT activation checklist
    • main.py — FastAPI app (port 8120) with /healthz, /api/p7/rooms, /api/p7/rooms/{id}, /api/p7/rooms/{id}/transition, /api/p7/reload
  • State machine: rehearsal → live (gated) → reviewarchive; same → same is idempotent no-op; archive is terminal
  • NATS subjects (canonical per spec §6): p7.nats.launch, p7.nats.session, room.session.updated.v1, pmoves.config.rooms.reloaded.v1 — all with signed envelopes (chit{kid, ts, status, signature})
  • Docker compose: new p7 service on profile=p7 (port 8120, NATS dep, rooms+schemas+sigcards+agent_registry volumes)
  • Make targets: up-p7, p7-health, smoke-p7

3. A2UI consumer (feat(p7): A2UI consumer ... + feat(p7): A2UI handler refactor ...)

  • pmoves/services/a2ui-nats-bridge/bridge.py: per-client subscriptions in the /ws/client WebSocket handler for room.session.updated.v1 and pmoves.config.rooms.reloaded.v1; payloads wrapped in {room: "p7-rooms", subject, data} envelopes (mirrors the geometry pattern)
  • Handlers extracted to module-level (forward_room_session_event, forward_config_reloaded_event) so unit tests can call them directly
  • New Prometheus counters: a2ui_room_session_events_forwarded_total, a2ui_room_config_reloaded_events_forwarded_total
  • All subscriptions have a clean unsubscribe() in the finally block

4. Operator + agent skills / commands

  • .claude/skills/p7-stage/SKILL.md: new procedural skill with three operations (claim, transition, observe), common-pitfalls table, full cross-references
  • .claude/commands/p7/stage.md: new operator slash command, sibling to /p7:room — thin wrapper over the P7 service HTTP API + NATS subjects
  • .claude/commands/p7/room.md: rewritten to match the aligned state machine, port 8120, transition endpoint, NATS subjects

5. Spec docs

  • pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md (operator-approved)
  • pmoves/docs/specs/p7-service-spec-2026-07-20.md (approved, design source-of-truth for the runtime)

Validation

Check Result
python pmoves/scripts/validate_room_manifests.py 9 / 9 OK (was 7 / 9 before — fordham + tokenism now pass)
pytest pmoves/services/p7-room-orchestrator/tests/ 46 / 46 passing (catalog + transition + nats_pub + api)
pytest pmoves/services/a2ui-nats-bridge/tests/ 16 / 16 passing (signature gate + room envelope)
python -c 'import main' (P7 service) clean
ast.parse on bridge.py clean
make -C pmoves smoke-p7 (operator gate — needs docker compose to actually run)

Operator gate

  • Schema extensions approved by DARKXSIDE on 2026-07-20 (per AGNOTE4482PHI.t1.md Mavis::OPEN-ROOM-LANE-SIGNOFF-RECEIVED entry)
  • The schema-extension spec doc (room-manifest-schema-extensions-2026-07-20.md) lists the operator signoff checklist — already satisfied
  • The P7 spec doc (p7-service-spec-2026-07-20.md) lists 5 open questions; the RELEASE entry documents the default resolutions taken (port 8120, P7's own CHIT card, catalog writeback directly, A2UI additive, worktree co-located)

Test plan for reviewer

# 1. Schema + manifest validation
python pmoves/scripts/validate_room_manifests.py
# expect: 9 OK / 0 FAILED

# 2. P7 service unit + integration tests (hermetic, no NATS needed)
cd pmoves/services/p7-room-orchestrator
pip install -r requirements.txt
pytest tests/ -v
# expect: 46 passed

# 3. A2UI bridge tests
cd ../a2ui-nats-bridge
pytest tests/ -v
# expect: 16 passed

# 4. Local service smoke
cd ../p7-room-orchestrator
P7_PMOVES_ROOT=../../.. python main.py
# → http://localhost:8120/healthz should return status=ok
# → curl http://localhost:8120/api/p7/rooms should return 9 rooms
# → POST transition rehearsal->live (with a card_id'd manifest) should succeed
# → POST transition rehearsal->live (without card_id) should return 422 with unchecked items

# 5. Operator UX
/p7:room status 4090-field.room.control
/p7:stage list
/p7:stage transition z890-infra.room.fabric live --reason "z890 brought up"

Risk + rollback

  • Schema changes are additive only (additionalProperties: true on the new meta field, new enum values). Existing 9 manifests validate without modification. Backward compatible.
  • Service port collision: 8092 (taken by pdf-ingest + publisher-discord) → 8120 (chosen as the first free port in the agent tier). Confirmed free.
  • Pre-existing p7-room-orchestrator: this PR rewrites it. The app.py deletion is the only "breaking" change; consumers of the old p7.room.session.*.v1 NATS subjects and /api/v1/rooms/{id}/start|pause|resume|end endpoints must migrate to the new shape. Per the AGNOTE, no in-fleet consumers were identified.
  • P7 unsigned-local mode: by default, transitions run with chit.status: "unsigned-local" if P7_SERVICE_CARD_ID is unset. CHIT checklist item 4 still passes because P7_ALLOW_UNSIGNED_LOCAL=true is the operator-acknowledged default. Production rollout should set P7_SERVICE_CARD_ID + P7_SIGNING_KEY.
  • Rollback: revert the merge. The first slice (feat(rooms): open-room-lane first slice) is independently revertable — the catalog and schema changes are non-destructive (catalog schema_version bump is the only outward-facing signal).

Follow-ups (NOT in this PR — separately tracked)

  • A2UI renderer surface update: when the A2UI lit bundle picks up the new p7-rooms envelope, the renderer can show a "Live" / "Rehearsal" badge on each room card. The bridge is wired; the renderer side is a small follow-up.
  • p7-stage skill is in .claude/skills/; the auto-invocation path can be enabled by Claude Code's skill-discovery (already on by default).
  • Embedding model suits: separate concern (from the rooms/MiniMax/model review); not touched here.
  • A chit_card first-class field on the room manifest, deprecating the free-form meta object: spec'd in the extension doc §3.3; not implemented.

Cross-references

  • AGNOTE trail: pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md (search Mavis::OPEN-ROOM-LANE — 7 entries: CLAIM + RELEASE + signoff-received + align-plan + consumer+skill + COMPLETE)
  • Lane spec: pmoves/docs/specs/p7-service-spec-2026-07-20.md
  • Schema extension spec: pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md
  • Canonical CHIT checklist: pmoves/docs/ROOM_MANIFEST_CONTRACT.md § CHIT Signing-Card Activation Checklist
  • Rooms-on-a-stage model: pmoves/docs/ROOMS_ON_A_STAGE.md
  • Operator commands: .claude/commands/p7/{room,stage}.md
  • Agent skill: .claude/skills/p7-stage/SKILL.md
  • A2UI bridge consumer: pmoves/services/a2ui-nats-bridge/bridge.py (function: forward_room_session_event / forward_config_reloaded_event)

Commits in this PR

96b4604276  fix(p7): schema stage field + test_api reload on clean branch
ba365cfc30  docs(agnote): open-room-lane first slice RELEASE entry
48803ba457  feat(p7): A2UI handler refactor + room-envelope tests + /p7:stage slash command
1c9507c3a3  feat(p7): A2UI consumer for room.session.updated.v1 + p7-stage skill
c3d3c3e681  docs(agnote): P7 runtime slice RELEASE entry
a2e1b0a6f5  feat(p7): align p7-room-orchestrator to approved rooms-on-a-stage spec
2de01381df  docs(agnote): operator decision — Option A
a78be8ae5d  docs(agnote): operator signoff received on schema extensions; P7 spec APPROVED
6b31224c52  feat(rooms): open-room-lane first slice — schema extensions + catalog + checklist

8 commits authored by the same local git identity (PMOVES auto-mode operator), 9 total in the PR (1 fixup for the clean branch).

CHIT trail unsigned-local (no CHIT_PASSPHRASE loaded in the Mavis session). agent_signature: ACK::Mavis::OPEN-ROOM-LANE-2026-07-20.

Summary by CodeRabbit

  • New Features

    • Added the P7 room stage manager with lifecycle stages: rehearsal, live, review, and archive.
    • Added room listing, status, transition, reload, and health-check capabilities.
    • Added live room lifecycle updates through the web interface.
    • Added CHIT validation for rehearsal-to-live activation, with clear failure details and idempotent repeat transitions.
  • Documentation

    • Added operator guides, service specifications, lifecycle references, and troubleshooting guidance.
  • Bug Fixes

    • Improved room manifest validation and catalog stage tracking.

… stage + checklist consolidation

Mavis open-room lane (mvs_09c9b116c675418b9d8b1a48b10867dc, 2026-07-20).

- schema: add 'exchange' to room_type.enum, 'browser' to panels[].kind, free-form 'meta' object at root (all provisional, pending operator signoff per AGNOTE4482 §1348)
- manifest: tokenism.room.exchange.skill_bindings now declare all required fields (skill_id, room_id, context.sources, outputs, guardrails)
- catalog: schema_version 1.1.0 → 1.2.0, all 9 rooms now have current_stage (3 live / 5 rehearsal / 1 archive) + stage_source + stage_verified_at
- docs: canonical CHIT activation checklist consolidated to ROOM_MANIFEST_CONTRACT.md; ROOMS_ON_A_STAGE.md + AGNOTE4482.md now link out
- docs: 'suits' → 'overlays' in room context to break collision with pmoves/configs/model-suits/
- spec: pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md (proposal for operator review)
- spec: pmoves/docs/specs/p7-service-spec-2026-07-20.md (P7 FastAPI runtime design — code in feat/p7-runtime-slice worktree, blocked on schema signoff)

validate_room_manifests.py: 7 OK / 2 FAILED → 9 OK / 0 FAILED.

AGNOTE4482PHI.t1.md: open-room lane CLAIM 2026-07-20T17:59:39Z.
Mavis open-room lane, Option A (mvs_09c9b116c675418b9d8b1a48b10867dc, 2026-07-20).

Aligns the pre-existing p7-room-orchestrator (planned/active/paused/ended/archived,
CHIT on chit.capability/handler/integration/trigger, NATS p7.room.session.*.v1,
port 8092, no compose entry) to the operator-approved spec at
pmoves/docs/specs/p7-service-spec-2026-07-20.md (rehearsal/live/review/archive,
CHIT on meta.chit.card_id, NATS p7.nats.* + room.session.updated.v1, port 8120,
atomic catalog writeback, schema-validated manifest loads).

- Split single-file app.py into:
  - config.py     Pydantic settings (P7_*-prefixed env vars)
  - catalog.py    CatalogLoader: load/cache/reload, atomic writeback of current_stage,
                  manifest validation against room.manifest.v1.schema.json
                  with skill.binding.v1.schema.json \ resolution (via referencing.Registry)
  - nats_pub.py   NATSPublisher: HMAC-SHA256 sign + publish to p7.nats.launch,
                  p7.nats.session, room.session.updated.v1, pmoves.config.rooms.reloaded.v1;
                  log-only fallback when NATS unreachable; unsigned-local status when
                  P7_SERVICE_CARD_ID/P7_SIGNING_KEY are unset
  - transition.py TransitionEngine: state machine + 7-item CHIT activation checklist
                  (canonical from ROOM_MANIFEST_CONTRACT.md)
  - main.py       FastAPI app: /healthz, /api/p7/rooms, /api/p7/rooms/{id},
                  /api/p7/rooms/{id}/transition, /api/p7/reload; exception handlers
                  for ManifestError/InvalidTransitionError/ChecklistError/CatalogError
  - README.md     operator + developer quickstart
  - tests/        46 pytest cases across test_catalog, test_transition, test_nats_pub,
                  test_api; hermetic conftest.py builds a temp pmoves/ subtree
- Dockerfile: port 8120, healthcheck, multi-file COPY
- requirements.txt: + jsonschema, + PyYAML, + pydantic-settings
- docker-compose.yml: p7 service on profile=p7 (port 8120, NATS dep,
  rooms+schemas+sigcards+agent_registry volumes)
- Makefile: up-p7, p7-health, smoke-p7 targets
- .claude/commands/p7/room.md: rewritten for new state machine, port 8120,
  transition endpoint, NATS subjects

Validation:
  pytest tests/                     46/46 passing
  validate_room_manifests.py        9/9 OK
  python -c 'import main'           OK (FastAPI app imports clean)

AGNOTE4482PHI.t1.md: open-room lane CLAIM 2026-07-20T17:59:39Z +
signoff-received 2026-07-20T19:45:00Z + align-plan 2026-07-20T19:50:00Z.
Mavis open-room lane, follow-on (mvs_09c9b116c675418b9d8b1a48b10867dc, 2026-07-20).

Two follow-ons from the P7 runtime slice:

- pmoves/services/a2ui-nats-bridge/bridge.py: per-client subscriptions to
  room.session.updated.v1 + pmoves.config.rooms.reloaded.v1 inside the
  /ws/client WebSocket handler. Payloads wrapped in {room: p7-rooms, subject,
  data} envelopes, mirroring the existing geometry pattern. New Prometheus
  counters: a2ui_room_session_events_forwarded_total,
  a2ui_room_config_reloaded_events_forwarded_total. All subscriptions get a
  clean unsubscribe in the finally block. Subject + room names are
  env-overridable (P7_ROOM_SESSION_UPDATED_SUBJECT, P7_CONFIG_RELOADED_SUBJECT,
  P7_WS_ROOM).

- .claude/skills/p7-stage/SKILL.md: new operator + agent skill with three
  operations - claim (read current_stage via GET /api/p7/rooms[/id]),
  transition (POST with body {target_stage, reason, requester}, gates on
  the 7-item CHIT checklist for rehearsal→live), observe (subscribe to
  room.session.updated.v1 / pmoves.config.rooms.reloaded.v1 via nats sub
  or via the A2UI WebSocket). Includes a common-pitfalls table and full
  cross-references.

Validation: ast.parse on bridge.py clean; P7 pytest suite still 46/46
(no regression). Code-only changes; no schema/catalog mutations.

AGNOTE4482PHI.t1.md: open-room lane CLAIM 2026-07-20T17:59:39Z +
signoff-received 2026-07-20T19:45:00Z + align-plan 2026-07-20T19:50:00Z +
RELEASE 2026-07-20T20:00:00Z + consumer+skill 2026-07-20T20:10:00Z.
…sh command

Mavis open-room lane, follow-on (mvs_09c9b116c675418b9d8b1a48b10867dc, 2026-07-20).

Refactor + new tests for A2UI bridge P7 envelope handlers + new operator
slash command for the P7 lifecycle.

- pmoves/services/a2ui-nats-bridge/bridge.py: extracted the two new P7
  handlers (room.session.updated.v1 + pmoves.config.rooms.reloaded.v1) from
  inside the client_websocket closure to module-level
  forward_room_session_event / forward_config_reloaded_event functions. The
  per-client closure versions delegate to the module-level so behavior is
  unchanged. Reason: the existing test pattern (importlib.util) re-registers
  prometheus_client Counter objects on each import; module-level handlers
  let us share one bridge instance across test files.

- pmoves/services/a2ui-nats-bridge/tests/test_signature_gate.py: 7 new
  test cases (room_session_handler_wraps_in_p7_rooms_envelope,
  room_session_handler_respects_env_override,
  room_session_handler_handles_garbage_payload,
  config_reloaded_handler_wraps_in_p7_rooms_envelope,
  config_reloaded_handler_handles_garbage_payload,
  test_subject_constants_match_p7_service_spec, test_p7_ws_room_default).
  Co-located in this file to share the bridge instance.

- .claude/commands/p7/stage.md: new operator slash command, sibling to
  /p7:room. claim (read), transition (mutate, gated), observe (subscribe).
  Backed by .claude/skills/p7-stage/SKILL.md; thin wrapper over the P7
  service HTTP API + NATS subjects. State-machine reference + common-pitfalls
  table.

Validation: A2UI bridge suite 15/15 passing; P7 service suite 46/46 passing;
bridge.py parses clean.

AGNOTE4482PHI.t1.md: open-room lane CLAIM 2026-07-20T17:59:39Z +
signoff-received + align-plan + RELEASE + consumer+skill + COMPLETE.
Two small fixes to the cherry-picked open-room lane branch:

- pmoves/contracts/schemas/room/room.manifest.v1.schema.json: 'stage' was
  a required root field (inherited from origin/main). The open-room lane
  spec (and the catalog schema v1.2.0 split) makes current_stage live
  in the catalog row, not the per-room manifest. The manifest's
  'stage' field is removed from required to match the spec.

- pmoves/services/p7-room-orchestrator/tests/test_api.py: add
  importlib.reload(main) to the client fixture so the SETTINGS singleton
  picks up P7_PMOVES_ROOT etc. set by hermetic_settings. Without the
  reload, SETTINGS is frozen at module import time and the catalog isn't
  found at the hermetic temp path.

- Remove the pre-Option-A test_app.py (tested the deleted single-file
  app.py). The new test_api.py covers the FastAPI surface.

Validation: validate_room_manifests.py 9/9 OK, P7 suite 46/46, A2UI bridge
suite 16/16.
@github-actions github-actions Bot added chit-aware Touches a CHIT-aware service — control-body signature gate applies compose Compose files / service Dockerfiles docs Documentation services Service source under pmoves/services/ config pmoves/config(s)/ changes governance AGNOTE register / agent definitions / damage-control hooks labels Jul 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Tue Jul 21 00:59:59 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: p7-room-orchestrator
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: p7_control_token
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 112 passed, 43 warnings, 0 errors

@github-actions

Copy link
Copy Markdown
Contributor

🔏 CHIT-aware change — control-body routing

This PR touches a CHIT-aware service (ports 8086/8087/8103/8106/8113/9224 surface). Before a Control-Body ACK:

  • the diff (or PR body) should reference a CHIT signature trail — chit.signed.v1, a CHIT: trailer, or a make -C pmoves sign-trail entry;
  • the chit-pr-audit-agent (.claude/agents/chit-pr-audit-agent.md) is the gate that grants/refuses ACK eligibility;
  • signing quickstart: pmoves/docs/AGENTS/CHIT_SIGNING_TUTORIAL.md.

Advisory routing only — the blocking contract check is CHIT Contract.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@POWERFULMOVES, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a08430e9-3002-4d9d-a698-52bc1693b50b

📥 Commits

Reviewing files that changed from the base of the PR and between 96b4604 and dac3fb8.

📒 Files selected for processing (17)
  • .claude/commands/p7/stage.md
  • .claude/skills/p7-stage/SKILL.md
  • pmoves/Makefile
  • pmoves/config/rooms/tokenism.room.exchange.json
  • pmoves/docker-compose.yml
  • pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md
  • pmoves/docs/ROOMS_ON_A_STAGE.md
  • pmoves/docs/specs/p7-service-spec-2026-07-20.md
  • pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md
  • pmoves/services/p7-room-orchestrator/Dockerfile
  • pmoves/services/p7-room-orchestrator/README.md
  • pmoves/services/p7-room-orchestrator/main.py
  • pmoves/services/p7-room-orchestrator/nats_pub.py
  • pmoves/services/p7-room-orchestrator/tests/conftest.py
  • pmoves/services/p7-room-orchestrator/tests/test_api.py
  • pmoves/services/p7-room-orchestrator/tests/test_app.py
  • pmoves/services/p7-room-orchestrator/transition.py
📝 Walkthrough

Walkthrough

Introduces a P7 room-aware stage manager on port 8120 with lifecycle transitions, CHIT gating, catalog persistence, NATS events, A2UI forwarding, updated room contracts, operator commands, Compose/Make integration, and hermetic test coverage.

Changes

P7 Room Lifecycle

Layer / File(s) Summary
Room contracts and lifecycle configuration
pmoves/config/rooms/*, pmoves/contracts/schemas/room/*, pmoves/docs/specs/*, pmoves/docker-compose.yml
Room stage metadata, manifest schema extensions, tokenism binding updates, Compose service wiring, and P7 specifications are added or revised.
Operator commands and lifecycle guidance
.claude/commands/p7/*, .claude/skills/p7-stage/*, pmoves/docs/*, pmoves/Makefile
Operator documentation defines claim, transition, and observe workflows, CHIT gating, lifecycle states, NATS subjects, and P7 startup and smoke-test commands.
P7 service runtime and transition engine
pmoves/services/p7-room-orchestrator/*
The FastAPI service loads and validates room manifests, persists stages atomically, enforces transitions and CHIT checks, publishes signed or unsigned-local NATS events, and exposes health, room, transition, and reload endpoints.
A2UI room-lifecycle event forwarding
pmoves/services/a2ui-nats-bridge/bridge.py
Room update and catalog reload subjects are subscribed to and forwarded to WebSocket clients as P7 room envelopes with metrics.
Hermetic runtime and bridge validation
pmoves/services/p7-room-orchestrator/tests/*, pmoves/services/a2ui-nats-bridge/tests/*
Tests cover catalog validation and persistence, API responses, state transitions, CHIT checklist failures, NATS payloads, and WebSocket forwarding behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant P7FastAPI
  participant TransitionEngine
  participant CatalogLoader
  participant NATSPublisher
  participant A2UIBridge
  participant WebSocketClient
  Operator->>P7FastAPI: Request room transition
  P7FastAPI->>TransitionEngine: Validate and execute transition
  TransitionEngine->>CatalogLoader: Read manifest and current stage
  TransitionEngine->>CatalogLoader: Persist updated current_stage
  TransitionEngine->>NATSPublisher: Publish room.session.updated.v1
  A2UIBridge->>WebSocketClient: Forward room envelope
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has summary and testing details, but it omits the template's Required Checks and Review Coordination sections. Add the Required Checks checklist items and a Review Coordination section, and keep the Summary and Testing sections in the template format.
Docstring Coverage ⚠️ Warning Docstring coverage is 24.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: P7 runtime plus schema/catalog and A2UI integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/open-room-lane

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Copy link
Copy Markdown

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: 96b4604276

ℹ️ 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 pmoves/services/p7-room-orchestrator/main.py Outdated
Comment thread pmoves/services/p7-room-orchestrator/transition.py Outdated
Comment thread pmoves/services/p7-room-orchestrator/Dockerfile Outdated
Comment thread pmoves/Makefile
Comment thread pmoves/services/p7-room-orchestrator/main.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pmoves/docs/AGENTS/AGNOTE4482.md (1)

1256-1265: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove the stale duplicate CHIT checklist.

The historical note says ROOM_MANIFEST_CONTRACT.md is the single source of truth, but this file still contains a full copy—and it has 8 items while the P7 docs state 7. Keep only the historical note and canonical link, or clearly archive the checklist so operators cannot follow conflicting gates.

As per path instructions, the CHIT activation checklist must have a single source of truth in ROOM_MANIFEST_CONTRACT.md.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/docs/AGENTS/AGNOTE4482.md` around lines 1256 - 1265, Remove or clearly
archive the duplicated CHIT activation checklist beneath the historical note in
AGNOTE4482.md, leaving only the note and canonical reference to
ROOM_MANIFEST_CONTRACT.md. Ensure operators cannot mistake this file for an
actionable checklist and preserve ROOM_MANIFEST_CONTRACT.md as the sole source
of truth.

Source: Path instructions

🧹 Nitpick comments (3)
pmoves/services/p7-room-orchestrator/main.py (1)

129-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fragile substring match to pick HTTP status for ManifestError.

404 if "not in catalog" in str(exc) else 422 couples the HTTP contract to catalog.py's exact error-message wording. Any future rewording of those messages silently changes the API's status codes. Prefer a structured attribute (e.g. ManifestError(msg, status_code=404), mirroring TransitionError's pattern) instead of string matching.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/services/p7-room-orchestrator/main.py` around lines 129 - 134, Update
ManifestError and _manifest_error_handler to use a structured status_code
attribute instead of checking for the “not in catalog” substring. Assign the
appropriate status code at each ManifestError construction site, defaulting to
422 where applicable, and return exc.status_code while preserving the existing
error response content.
pmoves/services/a2ui-nats-bridge/bridge.py (1)

162-165: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale docstring reference to a nonexistent test file.

Docstring says tests live in tests/test_room_envelope.py, but per this same layer they actually live in tests/test_signature_gate.py (as explicitly noted in that file's own comment). Update the reference to avoid sending future readers to a file that doesn't exist.

📝 Proposed fix
-    Module-level (not a closure) so unit tests in
-    ``tests/test_room_envelope.py`` can call it directly. Named
+    Module-level (not a closure) so unit tests in
+    ``tests/test_signature_gate.py`` can call it directly. Named
     ``forward_*`` (not ``*_handler``) to avoid shadowing the per-client
     closure in ``client_websocket``.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/services/a2ui-nats-bridge/bridge.py` around lines 162 - 165, Update
the module-level helper docstring near the forward_* functions to reference
tests/test_signature_gate.py instead of the nonexistent
tests/test_room_envelope.py, leaving the surrounding explanation unchanged.
pmoves/services/p7-room-orchestrator/tests/test_nats_pub.py (1)

65-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assertion-free test provides no real coverage.

test_publish_room_updated_shape invokes publish_room_updated but asserts nothing — it only proves the call doesn't raise. test_high_level_helpers_use_correct_subjects right below already verifies the same method's subject/payload shape via monkeypatching p.publish. Consider dropping this test (or merging its intent into the one below) so the name doesn't imply verification it doesn't perform.

🧪 Suggested cleanup
-@pytest.mark.asyncio
-async def test_publish_room_updated_shape():
-    p = NATSPublisher(nats_url="nats://127.0.0.1:1", service_card_id="", signing_key="")
-    await p.publish_room_updated(
-        room_id="x.room", previous_stage="rehearsal", new_stage="live",
-        reason="promotion", requester="DARKXSIDE",
-    )
-    # We can't inspect the publisher's internal call list without monkey-patching
-    # but the function should be side-effect-free in log-only mode.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pmoves/services/p7-room-orchestrator/tests/test_nats_pub.py` around lines 65
- 74, Remove the assertion-free test_publish_room_updated_shape, since
test_high_level_helpers_use_correct_subjects already verifies
publish_room_updated’s subject and payload through the mocked p.publish call. Do
not add redundant coverage; retain the existing meaningful subject/payload
assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/commands/p7/stage.md:
- Line 133: Fix the malformed troubleshooting table rows so each has exactly
three pipe-delimited cells: symptom, cause, and fix. In
.claude/commands/p7/stage.md lines 133-133, keep the NATS subject symptom and
remediation together in the fix cell; apply the same three-column correction to
the affected rows in .claude/skills/p7-stage/SKILL.md lines 149-156.

In @.claude/skills/p7-stage/SKILL.md:
- Around line 89-99: Update the transition procedure’s publish outcome in the
POST transition step to state that NATS publishes use either a signed or
unsigned-local envelope, depending on signing configuration, instead of claiming
every transition is signed.

In `@pmoves/docker-compose.yml`:
- Around line 2874-2887: Update the P7 service configuration to ensure its
FastAPI server binds to 0.0.0.0 by adding the host setting expected by the
application, such as P7_HOST. Add support for P7_SIGNING_KEY_FILE using the
repository’s established secret-file loading convention, while preserving
P7_SIGNING_KEY as the existing fallback.

In `@pmoves/docs/ROOMS_ON_A_STAGE.md`:
- Around line 62-69: Update the adjacent P7 deployment contract in the
documentation to reference service port 8120 and the current p7.nats.*
control-plane subjects, removing legacy port 8122 and p7.room.*.v1 references.
Keep the operational claims aligned with the current runbooks and smoke
evidence.

In `@pmoves/docs/specs/p7-service-spec-2026-07-20.md`:
- Around line 86-102: Update the P7 service layout, Docker Compose snippet, and
Makefile targets in the spec to match the implemented p7-room-orchestrator
service and evidence from runbooks/smokes. Replace p7 paths with
services/p7-room-orchestrator, place smoke tests under
services/p7-room-orchestrator/tests, and use the P7_-prefixed environment
variables, including P7_NATS_URL, P7_ROOM_CATALOG_PATH, P7_ROOMS_DIR, and
P7_CHIT_REQUIRE_SIGNATURE, consistently throughout the affected sections.

In `@pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md`:
- Around line 3-8: Make the schema-extension approval status consistent across
all references: in
pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md lines 3-8,
establish whether operator signoff is complete and update the status
accordingly; in .claude/commands/p7/room.md line 118, remove “operator-approved”
or link to approval evidence; in .claude/skills/p7-stage/SKILL.md lines 175-178,
align the cross-reference with that authoritative status; and in
pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md line 1236, retain the prior status only
when explicitly labeled historical.

In `@pmoves/services/p7-room-orchestrator/catalog.py`:
- Around line 74-91: Offload synchronous catalog disk I/O from the asyncio event
loop by wrapping calls to Catalog methods reload(), get_manifest(), and
_write_catalog_atomic() with asyncio.to_thread (or the existing executor
pattern) at their async call sites in TransitionEngine.transition() and the
get_room, list_rooms, and reload_catalog handlers in main.py. Preserve locking,
validation, return values, and exception behavior while ensuring reads, writes,
and fsync execute in a worker thread.

In `@pmoves/services/p7-room-orchestrator/main.py`:
- Around line 87-95: Replace the direct os.environ read in the PUBLISHER setup
with a required signing-key field on P7Settings, using the existing centralized
environment and *_FILE secret-loading helpers. Document the corresponding
environment variable in config.py, and ensure missing configuration fails loudly
rather than passing an empty key to NATSPublisher.

In `@pmoves/services/p7-room-orchestrator/nats_pub.py`:
- Around line 57-95: Update NATSClient.connect to use self._retry_max and
self._retry_backoff for bounded connection retries with backoff, returning
success immediately when connected and log-only failure only after all attempts
are exhausted. Ensure each failed attempt cleans up any partially created or
stale self._nc client before the next attempt, including mid-stream reconnects,
without changing the existing connected-state contract.

In `@pmoves/services/p7-room-orchestrator/README.md`:
- Around line 89-95: Update the Docker run example to set the P7_NATS_URL
environment variable instead of NATS_URL, preserving the host.docker.internal
endpoint so the service uses the configured NATS address.
- Around line 58-73: The P7 signing configuration documentation and
implementation must support file-based secrets and avoid defaulting to
unsigned-local operation. Update the signing-key configuration around P7's
signing setup to honor P7_SIGNING_KEY_FILE via the shared secret helper, and
change P7_ALLOW_UNSIGNED_LOCAL so it is explicitly enabled only for local
development rather than defaulting to true; keep fail-closed signature
enforcement as the default.

In `@pmoves/services/p7-room-orchestrator/transition.py`:
- Around line 216-230: Update the checklist flow around the card_id validation
so a missing or invalid card_id records items 1-3 as skipped but does not return
early; allow execution to continue through independent items 4-7. Remove the
duplicate self._find_signing_card(card_id) lookup below and ensure
card-dependent validation remains safely skipped when no valid card_id exists.
- Around line 283-312: The configuration sources used by checklist items 6 and 7
are inconsistent with the canonical sidecar config naming. Update the relevant
transition validation symbols, including _settings.resolved("pmoves/env.shared")
and _load_sidecar_env, so they use the documented canonical sidecar.env path, or
explicitly document and consistently support env.shared as its alias; ensure
item 7 validates the same source referenced by ROOM_MANIFEST_CONTRACT.md.

---

Outside diff comments:
In `@pmoves/docs/AGENTS/AGNOTE4482.md`:
- Around line 1256-1265: Remove or clearly archive the duplicated CHIT
activation checklist beneath the historical note in AGNOTE4482.md, leaving only
the note and canonical reference to ROOM_MANIFEST_CONTRACT.md. Ensure operators
cannot mistake this file for an actionable checklist and preserve
ROOM_MANIFEST_CONTRACT.md as the sole source of truth.

---

Nitpick comments:
In `@pmoves/services/a2ui-nats-bridge/bridge.py`:
- Around line 162-165: Update the module-level helper docstring near the
forward_* functions to reference tests/test_signature_gate.py instead of the
nonexistent tests/test_room_envelope.py, leaving the surrounding explanation
unchanged.

In `@pmoves/services/p7-room-orchestrator/main.py`:
- Around line 129-134: Update ManifestError and _manifest_error_handler to use a
structured status_code attribute instead of checking for the “not in catalog”
substring. Assign the appropriate status code at each ManifestError construction
site, defaulting to 422 where applicable, and return exc.status_code while
preserving the existing error response content.

In `@pmoves/services/p7-room-orchestrator/tests/test_nats_pub.py`:
- Around line 65-74: Remove the assertion-free test_publish_room_updated_shape,
since test_high_level_helpers_use_correct_subjects already verifies
publish_room_updated’s subject and payload through the mocked p.publish call. Do
not add redundant coverage; retain the existing meaningful subject/payload
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5c48a34d-dae6-45f3-bb66-89cff7623b07

📥 Commits

Reviewing files that changed from the base of the PR and between 3aee488 and 96b4604.

📒 Files selected for processing (32)
  • .claude/commands/p7/room.md
  • .claude/commands/p7/stage.md
  • .claude/skills/p7-stage/SKILL.md
  • pmoves/Makefile
  • pmoves/config/rooms/catalog.json
  • pmoves/config/rooms/tokenism.room.exchange.json
  • pmoves/contracts/schemas/room/room.manifest.v1.schema.json
  • pmoves/docker-compose.yml
  • pmoves/docs/AGENTS/AGNOTE4482.md
  • pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md
  • pmoves/docs/ROOMS_ON_A_STAGE.md
  • pmoves/docs/ROOM_MANIFEST_CONTRACT.md
  • pmoves/docs/specs/p7-service-spec-2026-07-20.md
  • pmoves/docs/specs/room-manifest-schema-extensions-2026-07-20.md
  • pmoves/services/a2ui-nats-bridge/bridge.py
  • pmoves/services/a2ui-nats-bridge/tests/test_signature_gate.py
  • pmoves/services/p7-room-orchestrator/Dockerfile
  • pmoves/services/p7-room-orchestrator/README.md
  • pmoves/services/p7-room-orchestrator/__init__.py
  • pmoves/services/p7-room-orchestrator/app.py
  • pmoves/services/p7-room-orchestrator/catalog.py
  • pmoves/services/p7-room-orchestrator/config.py
  • pmoves/services/p7-room-orchestrator/main.py
  • pmoves/services/p7-room-orchestrator/nats_pub.py
  • pmoves/services/p7-room-orchestrator/requirements.txt
  • pmoves/services/p7-room-orchestrator/tests/__init__.py
  • pmoves/services/p7-room-orchestrator/tests/conftest.py
  • pmoves/services/p7-room-orchestrator/tests/test_api.py
  • pmoves/services/p7-room-orchestrator/tests/test_catalog.py
  • pmoves/services/p7-room-orchestrator/tests/test_nats_pub.py
  • pmoves/services/p7-room-orchestrator/tests/test_transition.py
  • pmoves/services/p7-room-orchestrator/transition.py
💤 Files with no reviewable changes (1)
  • pmoves/services/p7-room-orchestrator/app.py

Comment thread .claude/commands/p7/stage.md Outdated
Comment thread .claude/skills/p7-stage/SKILL.md
Comment thread pmoves/docker-compose.yml
Comment thread pmoves/docs/ROOMS_ON_A_STAGE.md
Comment thread pmoves/docs/specs/p7-service-spec-2026-07-20.md Outdated
Comment thread pmoves/services/p7-room-orchestrator/nats_pub.py
Comment thread pmoves/services/p7-room-orchestrator/README.md
Comment thread pmoves/services/p7-room-orchestrator/README.md
Comment thread pmoves/services/p7-room-orchestrator/transition.py Outdated
Comment thread pmoves/services/p7-room-orchestrator/transition.py
hunnibear and others added 6 commits July 20, 2026 23:55
Addresses 5 P1 review threads from chatgpt-codex-connector + CodeQL:

- pmoves/services/p7-room-orchestrator/Dockerfile: COPY paths now assume
  monorepo-root build context (matching the existing p7-room-orchestrator
  compose definitions in docker-compose.yml and docker-compose.agents.yml).
  Sets P7_HOST=0.0.0.0 so the container bind is correct.

- pmoves/services/p7-room-orchestrator/main.py: restore bearer auth on
  /api/p7/rooms/{id}/transition via P7_CONTROL_TOKEN. Uses the shared
  services/common/env.py get_secret helper so P7_CONTROL_TOKEN_FILE works
  out of the box. Endpoints return 503 if the token is unconfigured
  (fail-closed) or 401 for invalid bearer credentials. Mirrors the
  original p7-room-orchestrator contract from origin/main app.py.

- pmoves/services/p7-room-orchestrator/main.py: add a global exception
  handler that logs the full exception server-side but returns a generic
  'internal_error' message to the client. Closes the CodeQL
  'information exposure through an exception' finding.

- pmoves/services/p7-room-orchestrator/transition.py: signing_cards.yaml
  parser now handles the canonical LIST shape used in
  pmoves/config/signing_identity_cards.yaml. The previous code only
  matched the DICT shape and silently failed for every rehearsal→live
  transition. Legacy DICT shape still supported for backward compat.

- pmoves/Makefile: restore up-cipher-full and cipher-memory-smoke
  targets. The 'feat(p7): align' commit accidentally dropped them when
  inserting the P7 targets next to up-cipher. Restoring the existing
  AGENT_TRAIL.md workflow.

- pmoves/docker-compose.yml: add P7_HOST=0.0.0.0 and P7_SIGNING_KEY_FILE
  env vars to the p7 service. Use the same build-context convention as
  the existing p7-room-orchestrator entries (context: ., dockerfile:
  services/p7-room-orchestrator/Dockerfile).

- pmoves/services/p7-room-orchestrator/tests/conftest.py: write signing
  cards in the canonical LIST shape (matches production) and set
  P7_CONTROL_TOKEN=test-control-token so the new auth dependency
  passes.

- pmoves/services/p7-room-orchestrator/tests/test_api.py: TestClient
  default headers include the bearer token so existing transition tests
  pass through the auth gate. Per-test override remains possible for
  the 401/503 auth paths.

Validation: validate_room_manifests.py 9/9 OK, P7 pytest 46/46 passing.
- transition.py: items 4-7 now evaluated when card_id is missing (not
  short-circuited), so the operator sees the full checklist state in a
  single iteration.
- transition.py: rename 'sidecar.env' → 'env.shared' in items 6/7 to
  match the canonical filename (per pmoves/env.shared).
- transition.py: _load_sidecar_env now merges process env (wins) over
  the file contents so tests + runtime overrides work cleanly.
- main.py: offload CATALOG.reload() and CATALOG.get_manifest() (disk
  I/O + JSON schema validation) via asyncio.to_thread so the event
  loop isn't blocked during /api/p7/reload and /api/p7/rooms/{id}.
- transition.py: offload CATALOG.get_manifest() and CATALOG.update_stage()
  in the transition path.
- main.py: P7_SIGNING_KEY now goes through get_secret() so the
  P7_SIGNING_KEY_FILE secret-mount pattern works (mirrors the
  P7_CONTROL_TOKEN handling).
- nats_pub.py: implement connect_with_retry() using retry_max_attempts
  and retry_backoff_sec with exponential backoff (cap 60s). Lifespan
  now calls connect_with_retry() for bounded boot-time retries; the
  one-shot connect() is kept for lazy publish-time fallback.
- tests/test_api.py: add FakePublisher.connect_with_retry().

All tests green: 46/46 P7, 16/16 A2UI, 9/9 manifests.
- README.md: signing key FILE support documented (P7_SIGNING_KEY_FILE),
  Docker example uses P7_NATS_URL not NATS_URL, new 'Secret-aware env'
  section covers the *_FILE pattern with Docker + local-dev examples.
- ROOMS_ON_A_STAGE.md: P7 deployment contract updated to reflect
  FastAPI service at pmoves/services/p7-room-orchestrator on port 8120
  with the actual HTTP API + NATS subject table + signed/unsigned-local
  envelope contract (was 'port 8122' + 'p7.room.*.v1', both stale).
- p7-service-spec-2026-07-20.md: status APPROVED, branch
  feat/open-room-lane, file layout corrected to p7-room-orchestrator
  dir, docker-compose snippet uses the real P7_*-prefixed env vars
  (was NATS_URL / PMOVES_ROOMS_CATALOG / PMOVES_ROOMS_DIR /
  CHIT_REQUIRE_SIGNATURE), open questions replaced with resolved
  decisions, signoff checklist marked all-checked.
- room-manifest-schema-extensions-2026-07-20.md: status APPROVED, branch
  feat/open-room-lane, signoff checklist marked all-checked with the
  CLAIM + RELEASE references in AGNOTE4482PHI.t1.md.
- .claude/commands/p7/stage.md: 'Common pitfalls' table row for NATS
  no-traffic fixed (the inline pipe in 'curl ... | jq ...' was being
  parsed as a column separator, breaking the 2-column table).
- .claude/skills/p7-stage/SKILL.md: 'Signed NATS publish' wording
  relaxed to make the signed/unsigned-local distinction explicit
  (was misleading — implies all publishes are signed).

All tests still green: 46/46 P7, 16/16 A2UI, 9/9 manifests.
Records the 3 review-iter commits (a3813dc / e1f6d15 / 249a38b)
that addressed all 18 review threads on PR #2173.

This AGNOTE entry is the trail-of-record for the review-iter-1 push. The
intermediate entries that lived on the operator's auto worktree
(operator signoff, align-plan, runtime slice RELEASE, A2UI consumer+skill)
are summarized inline so the trail on this branch is self-contained.
… reconnect

- get_room now logs the ManifestError (which embeds internal filesystem
  paths) and returns a generic manifest_error to the caller, closing the
  CodeQL py/stack-trace-exposure alert at main.py.
- NATSPublisher.connect() drains any stale self._nc before creating a new
  client, so a mid-stream publish failure (_connected=False) no longer leaks
  the previous connection on reconnect (CodeRabbit Major).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nats_connected check cell contained an unescaped ` | ` inside its code
span, which GFM parses as a 4th column and breaks the 3-column table render
(CodeRabbit Minor / table-column-count). stage.md's 2-col table was already
clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflicts resolved:
- tokenism.room.exchange.json: keep BOTH the branch's guardrails block
  (schema-completion work) and main's enabled:true (the W2 flip, #2169,
  live-verified — must not regress).
- AGNOTE4482PHI.t1.md: append-collision, keep-both (branch's GRAPHITI
  mark + main's sections).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Sat Jul 25 12:23:34 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: p7-room-orchestrator
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: p7_control_token
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 112 passed, 43 warnings, 0 errors

@POWERFULMOVES
POWERFULMOVES merged commit be1059a into main Jul 25, 2026
36 of 37 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the feat/open-room-lane branch July 25, 2026 12:24
POWERFULMOVES added a commit that referenced this pull request Jul 25, 2026
…rofiles, broker auth (#2223)

Landed #2173 and stood P7 up on 5090; five defects surfaced at first
real boot, each verified fixed live (healthz ok, rooms_loaded=9,
nats_connected=true, smoke 46/46):

1. main.py crashed in-container: Path(__file__).parents[3] raises
   IndexError at /app/main.py before the ImportError fallback can
   engage (restart loop). Now walks upward for services/common — and
   APPENDS to sys.path: services/common ships its own config.py which
   would otherwise shadow the service's config module. (The old fixed
   index accidentally never resolved in-repo either, so the shared
   env helper was silently unused everywhere; tests now import the
   real one.)
2. Fallback get_secret ignored the <KEY>_FILE convention — compose
   delivers P7_SIGNING_KEY_FILE, which would silently never load
   in-container.
3. up-p7 used --profile agents, activating the legacy
   p7-room-orchestrator whose supabase-kong dependency is
   profile-gated — compose fails the whole project as 'depends on
   undefined service'. New p7 needs only --profile p7.
4. Legacy service's kong dependency marked required:false so ANY
   --profile agents invocation resolves again without supabase-local.
5. P7_NATS_URL lacked broker credentials — P7 booted log-only
   (nats_connected:false, no signed lifecycle events). Also: p7-health
   now retries (up-p7 chains into it before the container finishes
   booting) and smoke-p7 runs pytest from the service dir (flat-module
   imports).

Co-authored-by: Shaela Bello <slbello@uncg.edu>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chit-aware Touches a CHIT-aware service — control-body signature gate applies compose Compose files / service Dockerfiles config pmoves/config(s)/ changes docs Documentation governance AGNOTE register / agent definitions / damage-control hooks services Service source under pmoves/services/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants