Skip to content

feat(a2ui-renderer): first-class compose + render script + freshness check + registry (#2228) - #2349

Merged
POWERFULMOVES merged 3 commits into
mainfrom
feat/a2ui-renderer-compose-2228
Aug 2, 2026
Merged

POWERFULMOVES merged 3 commits into
mainfrom
feat/a2ui-renderer-compose-2228

Conversation

@POWERFULMOVES

Copy link
Copy Markdown
Owner

feat(a2ui-renderer): first-class compose stanza + render script + freshness check + registry (Issue #2228)

Lane 2228 (2026-08-02): a2ui-renderer was a service-source orphan —
TypeScript service at pmoves/services/a2ui-renderer/ existed,
Remotion bundle compiled, /render/provenance endpoint worked, but
no compose stanza + no Makefile target + no registry saying "render
this doc into a living artifact". This lane makes it a first-class
fleet capability.

3 stacked commits

SHA Type Files Lines
0552b1537c P1: feat(compose+a2ui) 3 +156/-5
0406ad082d functional: feat(tools+a2ui) 5 +1497
292df1819f docs: AGNOTE CLAIM + spec 2 +275

What lands

1. Compose stanza + Makefile tokens + registry (P1)

  • pmoves/docker-compose.yml: a2ui-renderer service stanza
    • port 8107, profiles agents media docs (was the nonexistent creator profile)
    • depends_on nats+minio health-checked
    • tier-agent-hardened-ro
    • CHIT fail-closed signing (mirrors hi-rag-gateway* pattern)
    • Supabase JWT for /render + /render/chart + /render/provenance
    • healthcheck via wget -qO- http://localhost:8107/healthz (per the YAML flow-sequence escaping lesson)
    • deploy limits 1.0 CPU / 1G memory
  • pmoves/Makefile: 5 targets (up-a2ui-renderer, down-a2ui-renderer, a2ui-renderer-smoke, a2ui-renderer-render, docs-render-living) + 3 tokens (A2UI_RENDERER_PORT, A2UI_RENDERER_TOKEN, A2UI_RENDERER_RENDER_DIR)
  • pmoves/configs/living_docs_registry.yaml: new renderable: section with 5 entries (existing tracked: section unchanged)

2. Living-docs hook — render script + freshness check + 18-test smoke suite (functional)

  • pmoves/tools/a2ui_renderer/render_living_doc.py (612 lines, stdlib-only):
    • Single-doc mode (--doc <md> --output <mp4>) + registry mode (--registry <yaml> --output-dir <dir>)
    • Markdown parser builds a ProvenanceLivingDoc that matches the TS service's normalizeProvenanceLivingDoc() contract 1:1 (4 sections max, 8 weighted terms max, 6 provenance refs max, merkle_root = mkl_ + sha256[:16], shape_id = shape.doc. + sha256[:16], duration_ms mirrors estimateProvenanceDurationMs() exactly)
    • --dry-run writes the request body without HTTP
    • --print-doc dumps the parsed doc for debugging
    • Forces UTF-8 on stdout/stderr at module-load so it's portable from Windows charmap without PYTHONIOENCODING
  • pmoves/tools/a2ui_renderer/check_renderable_freshness.py (130 lines): walks the renderable: section, classifies each entry as stale based on source mtime vs ttl_days, JSON report on stdout + summary on stderr, --strict exits non-zero
  • pmoves/tools/a2ui_renderer/test_render_living_doc.py (18 tests, all pass on a clean python test_render_living_doc.py): MarkdownParserTests (10), RegistryLoaderTests (3), DryRunTests (1), FullPathTests (2, in-process mock renderer), ErrorPathTests (2)
  • pmoves/tools/a2ui_renderer/__init__.py + README.md (60 lines): operator quick-start

3. AGNOTE CLAIM + cold-read spec (docs)

  • pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md: new section "Lane 2228 - a2ui-renderer compose lane SHIPPED (2026-08-02)" with the full CLAIM text
  • pmoves/docs/specs/a2ui-renderer-compose-2026-08-02.md (new, 11.9KB): cold-read spec

Validation

Check Result
python pmoves/tools/a2ui_renderer/test_render_living_doc.py 18/18 OK
ruff check pmoves/tools/a2ui_renderer/ All checks passed!
docker compose config --services | grep a2ui-renderer shows a2ui-renderer
Dry-run on pmoves/docs/PMOVESCHIT/VISUAL_TOUR.md 4 sections, 8 weighted terms, merkle mkl_173c4ba26932179e
check_renderable_freshness.py --strict 5 entries, 0 stale

Out of scope (intentional)

  • GHCR publishing for the heavy Chromium image (separate lane with the same shape as tokenism-simulator's GHCR promotion)
  • Cross-node NATS mesh for the a2ui-renderer publisher (depends on the cross-node leaf topology lane)
  • Re-render automation cron (freshness check is the advisor; the operator triggers the render)
  • Pretext submodule wiring for the chit-tour living-doc source (Issue feat(submodule): wire Pmoves-pretext — the layout half of the living-docs animation combo #2227, a sister issue)

Follow-up lanes

  1. GHCR publishing for a2ui-renderer
  2. Wire make docs-render-living into the docs-freshness village-gate
  3. Issue feat(submodule): wire Pmoves-pretext — the layout half of the living-docs animation combo #2227 (Pretext submodule for the chit-tour living-doc)
  4. make docs-render-living cron (7-day cadence, re-render stale entries)
  5. Cross-node NATS mesh for the a2ui-renderer publisher

Three-body

  • delivery: Mavis (this lane)
  • control: DARKXSIDE (PR review + 5 required gates + admin-merge)
  • memory: AGNOTE CLAIM + spec doc + 3 commits + 5 registry entries + 18 new test cases + the freshness check

Refs: #2228

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next review available in: 12 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: 044992b9-a9b7-4291-8ca9-3ca6b3af59c9

📥 Commits

Reviewing files that changed from the base of the PR and between 0faa2a2 and 3c5f6aa.

📒 Files selected for processing (12)
  • pmoves/Makefile
  • pmoves/configs/living_docs_registry.yaml
  • pmoves/docker-compose.agents.yml
  • pmoves/docker-compose.core.yml
  • pmoves/docker-compose.yml
  • pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md
  • pmoves/docs/specs/a2ui-renderer-compose-2026-08-02.md
  • pmoves/tools/a2ui_renderer/README.md
  • pmoves/tools/a2ui_renderer/__init__.py
  • pmoves/tools/a2ui_renderer/check_renderable_freshness.py
  • pmoves/tools/a2ui_renderer/render_living_doc.py
  • pmoves/tools/a2ui_renderer/test_render_living_doc.py

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.

@github-actions github-actions Bot added compose Compose files / service Dockerfiles docs Documentation config pmoves/config(s)/ changes governance AGNOTE register / agent definitions / damage-control hooks labels Aug 2, 2026

@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: 292df1819f

ℹ️ 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/docker-compose.yml
Comment on lines +3605 to +3607
build:
context: .
dockerfile: services/a2ui-renderer/Dockerfile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Point the Docker build context at the renderer service

The build context resolves to pmoves/, while services/a2ui-renderer/Dockerfile begins with COPY package.json package-lock.json* ./; there is no pmoves/package.json, only pmoves/services/a2ui-renderer/package.json. Consequently the documented make -C pmoves up-a2ui-renderer path invokes docker compose ... --build and fails before the image can be built. Set the context to services/a2ui-renderer (and adjust the Dockerfile path accordingly).

Useful? React with 👍 / 👎.

Comment thread pmoves/Makefile
Comment on lines +3917 to +3920
docs-render-living: ## Render all LIVING_DOCS_INDEX-registered docs through a2ui-renderer
@echo "Rendering living docs from pmoves/config/living_docs_registry.yaml..."
@mkdir -p $(A2UI_RENDERER_RENDER_DIR)
@uv run --script pmoves/tools/a2ui_renderer/render_living_doc.py \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace the existing docs-render-living target

This new registry iterator never runs because the same Makefile defines docs-render-living again at line 4290; GNU Make warns that it is overriding this recipe and executes tools/render_living_docs.py instead. Thus the documented make -C pmoves docs-render-living command does not read the new registry or invoke render_living_doc.py; remove or rename the later definition rather than adding a duplicate target.

Useful? React with 👍 / 👎.

Comment on lines +721 to +724
server.add_argument(
"--token",
default=os.environ.get("A2UI_RENDERER_TOKEN") or os.environ.get("SUPABASE_JWT_SECRET"),
help="Supabase JWT for /render/provenance (default: $A2UI_RENDERER_TOKEN or $SUPABASE_JWT_SECRET)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use a signed JWT instead of the JWT signing secret

When callers follow the default or README and only set SUPABASE_JWT_SECRET, this passes the raw signing secret as the bearer token. The renderer's requireAuth middleware calls jwt.verify(token, SUPABASE_JWT_SECRET), so the raw secret is rejected as a malformed JWT and every real render returns 401. Default to an actual signed credential such as the service-role JWT, while retaining the secret only in the renderer container for verification.

Useful? React with 👍 / 👎.

Comment thread pmoves/docker-compose.yml
Comment on lines +3643 to +3644
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8107/healthz >/dev/null 2>&1 || exit 1"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Run the healthcheck with the installed curl binary

The runtime Dockerfile installs curl, not wget, and its own image healthcheck consequently uses curl. This Compose override instead invokes wget, so after the build-context issue is fixed the command still exits with wget: not found and Docker permanently marks the renderer unhealthy. Use the already-installed curl command or install wget in the runtime image.

Useful? React with 👍 / 👎.

Comment on lines +641 to +645
if minio_bucket and not dry_run and result.get("minio_url"):
# The renderer already uploaded to MinIO; we just record the
# canonical key for downstream consumers.
result["canonical_minio_key"] = f"a2ui/living-docs/{output_key}.{fmt}"
result["canonical_minio_uri"] = f"s3://{minio_bucket}/{result['canonical_minio_key']}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Upload artifacts under the reported canonical key

In registry mode with --minio-bucket, these lines report a2ui/living-docs/<output_key>.<format> as the canonical object, but no upload or copy to that key occurs. The renderer actually uploaded a randomly named a2ui/provenance/<timestamp>-<random>.<format> object, so downstream consumers using canonical_minio_uri receive a nonexistent location even though the result is marked successful. Copy/upload the artifact to the canonical key or report the renderer's real key instead.

Useful? React with 👍 / 👎.

Comment on lines +65 to +67
"ttl_days": ttl_days,
}
mtime = source.stat().st_mtime

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Compare source changes against the rendered artifact

Freshness is calculated solely from the source file's age relative to the current time, without inspecting whether an artifact exists or when it was rendered. Therefore a newly rendered document whose source is older than its TTL remains stale forever, while a newly edited source with no rendered artifact is reported fresh until its TTL expires. Track the artifact timestamp and mark entries stale when the artifact is absent, older than the source, or beyond the intended render TTL.

Useful? React with 👍 / 👎.

@POWERFULMOVES
POWERFULMOVES force-pushed the feat/a2ui-renderer-compose-2228 branch from 292df18 to 293c5db Compare August 2, 2026 13:29
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Sun Aug 2 13:29:32 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

…le tokens + registry extension

Lane 2228 (2026-08-02): a2ui-renderer was a service-source orphan — the
TypeScript service at pmoves/services/a2ui-renderer/ existed, the Remotion
bundle compiled, the /render/provenance endpoint worked, but there was no
compose stanza, no Makefile target, and no registry saying "render this doc
into a living artifact". This P1 commit fixes all three.

What lands:
  - pmoves/docker-compose.yml: a2ui-renderer service stanza
      - port 8107, profiles agents/media/docs (3 profiles for the 3 callers)
      - depends_on nats+minio (health-checked)
      - tier-agent-hardened-ro
      - CHIT fail-closed signing (mirrors hi-rag-gateway* pattern)
      - Supabase JWT for /render, /render/chart, /render/provenance
      - healthcheck via wget (not node -e, see lane 2228 spec)
      - deploy limits 1.0 CPU / 1G memory
  - pmoves/Makefile:
      - up-a2ui-renderer (was --profile creator → now --profile agents --profile media --profile docs)
      - down-a2ui-renderer (new, was missing)
      - a2ui-renderer-smoke (extended to show /metrics counters)
      - a2ui-renderer-render (new, single-doc helper)
      - docs-render-living (new, registry iterator)
      - tokens: A2UI_RENDERER_PORT, A2UI_RENDERER_TOKEN, A2UI_RENDERER_RENDER_DIR
  - pmoves/configs/living_docs_registry.yaml:
      - new renderable: section with 5 entries (chit-visual-tour-walkthrough,
        agnote-active-claims, services-catalog-dashboard, a2ui-renderer-readme,
        chit-tour-public)
      - existing tracked: section unchanged

The functional commit (render script + freshness check + 18-test smoke suite)
follows on this branch. The docs commit (AGNOTE CLAIM + cold-read spec)
closes the lane.

Refs: #2228
See-also: pmoves/docs/specs/a2ui-renderer-compose-2026-08-02.md (functional commit)
…y + 18-test smoke suite

Lane 2228 (2026-08-02): the scriptable surface for the a2ui-renderer living-doc
lane. P1 brought the service up; this commit is what makes `make docs-render-living`
actually do something.

What lands:
  - pmoves/tools/a2ui_renderer/render_living_doc.py (new, 612 lines):
      - Single-doc mode: --doc <md> --output <mp4> --format mp4|gif|webm
      - Registry mode: --registry <yaml> --output-dir <dir> --minio-bucket <b>
      - Dependency-free (stdlib only), runs as a uv script shim
      - Markdown parser handles H1/H2/H3, builds ProvenanceLivingDoc shape
        that matches the TS service's normalizeProvenanceLivingDoc() contract
        (4 sections max, 8 weighted terms max, 6 provenance refs max)
      - merkle_root = sha256(normalized content)[:16] prefixed with mkl_
      - shape_id = sha256(source path)[:16] prefixed with shape.doc.
      - duration_ms mirrors estimateProvenanceDurationMs() 1:1
      - --dry-run: parse + dump request body, no HTTP
      - --print-doc: debug helper to inspect the parsed ProvenanceLivingDoc
      - Forces UTF-8 on stdout/stderr (Windows charmap breaks on non-ASCII)
  - pmoves/tools/a2ui_renderer/check_renderable_freshness.py (new, 130 lines):
      - Reads renderable: section of living_docs_registry.yaml
      - Classifies each entry: stale if source mtime > ttl_days, or missing
      - JSON report on stdout, one-line summary on stderr
      - --strict exits non-zero if any entry is stale (advisory hook target)
  - pmoves/tools/a2ui_renderer/test_render_living_doc.py (new, 18 tests):
      - MarkdownParserTests (10): H1→title, H2→sections, cap enforcement,
        merkle determinism, shape_id stability, fallback behavior, schema
      - RegistryLoaderTests (3): loads renderable section, excludes tracked,
        handles empty case
      - DryRunTests (1): writes valid JSON, no HTTP traffic
      - FullPathTests (2): posts to in-process mock, downloads the result,
        iterates a registry end-to-end
      - ErrorPathTests (2): missing source raises, unsupported format raises
  - pmoves/tools/a2ui_renderer/__init__.py (new, 1 line): package marker
  - pmoves/tools/a2ui_renderer/README.md (new, 60 lines): operator quick-start

All 18 tests pass on a clean `python pmoves/tools/a2ui_renderer/test_render_living_doc.py`.
ruff check: All checks passed!

Refs: #2228
See-also: pmoves/docs/specs/a2ui-renderer-compose-2026-08-02.md (docs commit)
…lane (2228)

Lane 2228 (2026-08-02): closes the lane. The CLAIM goes on the AGNOTE
(matching the Lane 5 forward-looking RELEASE pattern, since admin-merge
is the operator's call); the cold-read spec captures the full design
for a fresh local model picking this work up next session.

What lands:
  - pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md: new section "Lane 2228 -
    a2ui-renderer compose lane SHIPPED (2026-08-02)" with the full CLAIM
    text (root cause, what shipped, validation, out of scope, three-body,
    CHIT trail). Ends with the GRAPHITI_MARK HTML comment so a future
    graphiti loader can index it.
  - pmoves/docs/specs/a2ui-renderer-compose-2026-08-02.md (new, 11.9KB):
    cold-read spec covering TL;DR + why now + what shipped (P1 / func /
    registry) + how to use (5-step recipe) + validation table + out of
    scope (5 items) + follow-up lanes (5 items) + three-body + CHIT trail.

The PR is ready to push after this commit lands: 3 stacked commits, all
tests pass, ruff clean, YAML valid, dry-run produces a valid
ProvenanceLivingDoc, freshness check reports 0 stale entries.

Refs: #2228
@POWERFULMOVES
POWERFULMOVES force-pushed the feat/a2ui-renderer-compose-2228 branch from 293c5db to 3c5f6aa Compare August 2, 2026 13:32
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Sun Aug 2 13:33:07 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 8a377b3 into main Aug 2, 2026
34 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the feat/a2ui-renderer-compose-2228 branch August 2, 2026 13:38
POWERFULMOVES added a commit that referenced this pull request Aug 3, 2026
…SHIPPED + 3-PR triage batch (#2354)

The 2026-08-02 closeout (PR #2345) left Lane 5 as a forward-looking RELEASE
("squash pending — PR #2344 open") and Lane 2228 as a forward-looking CLAIM
("this CLAIM becomes a RELEASE on admin-merge"). Both are now actually
shipped. Plus a 3-PR triage batch that was DIRTY/BEHIND on main `a5320d7e3a`.

What lands in the AGNOTE:
  - Lane 5 RELEASE: confirms squash 2cba394 (PR #2344) with full validation
    + the 2 follow-up items still open (village-gate wire-in + TOKENISM_ATTRIBUTION
    interest→limits migration).
  - Lane 2228 RELEASE: promotes the PR #2349 CLAIM to RELEASE, names the actual
    squash 8a377b3, references Issue #2228 closure.
  - 3-PR triage batch: PR #2352 (chit-visual-tour-codegrounded, the real answer
    to #2343 I closed yesterday), PR #2346 (yt-cookies fresh key), PR #2353
    (monitoring mount paths — the VHDX-fill root cause).

Refs: #2228
Squashes referenced: 2cba394, 8a377b3, 6178bda, 1bf7ed6, 2dcbf25

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

Labels

compose Compose files / service Dockerfiles config pmoves/config(s)/ changes docs Documentation governance AGNOTE register / agent definitions / damage-control hooks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants