Repository navigation
audit(docs): PR bodies + ROADMAP + merge plan verification (H3D-CLAUDE-POLISH-RELEASE-DOCS-2026-05-06) - #78
Conversation
…cation (H3D-CLAUDE-POLISH-RELEASE-DOCS-2026-05-06) - Audited all 20 PR bodies (#53-#72): all have evidence chain, task ID, and gates - PR #53 missing formal files table (prose description present); PR #64 minimal body - TS7026 blocker documented in PR #72; absent from ROADMAP.md (codex-master locked) - README "77 of 79" claim is stale relative to feature branch (update post-merge) - Merge Tier 1/2/3 structure is correct; PR #72 needs explicit Tier 4 slot in plan - No PRs accidentally merged; all 20 lane PRs remain open Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive release and documentation audit report for PRs #53 through #72. The audit evaluates PR body completeness, roadmap accuracy, and README claims, identifying five documentation gaps including stale feature counts and missing merge tier assignments. Review feedback highlights a logical inconsistency regarding the merge order of the integration report and identifies an additional documentation gap concerning a missing contract file reference that should be tracked.
| - #66 and #69 absent from Tier 1 — correct, they have an app.py conflict. | ||
| - #72 absent from all tiers — as noted above, it should be explicitly listed as Tier 4 (post-Tier 3 singleton). | ||
|
|
||
| **Gap**: The merge plan does not assign #72 to any merge tier. Since it is a docs-only PR with no code conflicts, it can be merged at any point after the other 19, or first (no conflicts). The missing assignment is a documentation gap only. |
There was a problem hiding this comment.
Suggesting that PR #72 can be merged 'first' is logically inconsistent with its purpose as an integration report for PRs #53–#71. An integration report should follow the work it documents to maintain a valid audit trail. Please remove the 'or first' option to align with the Tier 4 recommendation in the summary table.
| **Gap**: The merge plan does not assign #72 to any merge tier. Since it is a docs-only PR with no code conflicts, it can be merged at any point after the other 19, or first (no conflicts). The missing assignment is a documentation gap only. | |
| Gap: The merge plan does not assign #72 to any merge tier. Since it is a docs-only PR with no code conflicts, it should be merged as a Tier 4 singleton after the other 19 PRs are integrated. The missing assignment is a documentation gap only. |
| | 2 | LOW | PR #64 body is a single paragraph with no section headers | Optional: standard body format not enforced in contract | | ||
| | 3 | MEDIUM | PR #72 merge plan (Tier 1/2/3) does not assign #72 to any tier | Add Tier 4 note: merge #72 after Tier 3; add to PR #72 test plan checklist | | ||
| | 4 | MEDIUM | ROADMAP.md does not document TS7026/TS7006 pre-existing regression | Add to Finish Queue after codex-master lock expires | | ||
| | 5 | LOW | README "77 of 79 user-visible features are real today" is stale relative to feature branch | Update post-merge in a README-sync PR | |
There was a problem hiding this comment.
The audit identifies that CLAUDE_20_AGENT_COMPLETION_CONTRACT.md is missing from the worktree (Line 119), yet it remains a primary reference in ROADMAP.md (Line 290). This broken reference is a significant documentation gap and should be included in this summary table for tracking.
| | 5 | LOW | README "77 of 79 user-visible features are real today" is stale relative to feature branch | Update post-merge in a README-sync PR | | |
| | 5 | LOW | README "77 of 79 user-visible features are real today" is stale relative to feature branch | Update post-merge in a README-sync PR | | |
| | 6 | MEDIUM | ROADMAP.md references missing CLAUDE_20_AGENT_COMPLETION_CONTRACT.md | Restore missing contract file or update ROADMAP reference | |
30661b9
into
feat/hermes3d-7-complete-gui-repo-wiring
* docs(contract): sync Hermes3D completion roadmap and Claude handoffs
WIP checkpoint per GITHUB_SYNC_PLAN_2026-05-06: contract docs, roadmap,
and 20-agent handoff before Claude lanes branch off this baseline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(api): add live Hermes3D backend routes and proof services
WIP checkpoint per GITHUB_SYNC_PLAN_2026-05-06: API routes, services,
db schema/init, core orchestration + slicer/printer adapters baseline
for the 20-agent completion lanes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): wire live Hermes3D tabs and remove mock UX
WIP checkpoint per GITHUB_SYNC_PLAN_2026-05-06: live tab shells
(Source OS, Settings, Agents, Observe, Roadmap, Plugins, Jobs,
Artifacts, Approvals, Voice, Learning, Autopilot, Design, 3D Generation,
Printers), live API adapters, ResizablePane/AppShell layout, and
removal of mock data + retired tabs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(source-os): add adapter schemas, source audits, and runtime proof
WIP checkpoint per GITHUB_SYNC_PLAN_2026-05-06: 31 adapter_registry
JSON schemas (slicers/modelers/print-farm/gen3D/firmware), source-app
audit scripts, and proof artifacts (CLI surface, runtime action plan,
local tooling audit) backing the Source OS lane.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(e2e): add live GUI and no-fake proof coverage
WIP checkpoint per GITHUB_SYNC_PLAN_2026-05-06: Playwright e2e config
and live-gui spec, runtime-port + GUI-API + e2e-stack starters; retire
visual specs replaced by the live e2e suite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(fix): extend ui-ci.yml PR trigger to feat/** branches (TS7026 root cause) (#80)
* ci(fix): extend ui-ci.yml PR trigger to feat/** branches
`pull_request.branches` previously only listed `[main, develop]`.
Lane PRs target `feat/hermes3d-7-complete-gui-repo-wiring`, so
`npm ci` + `tsc --noEmit` (Layer D2) never ran for them.
Adding `feat/**` ensures the strict lint gate fires on every lane
PR, surfacing the pre-existing TS7026/TS7006 JSX.IntrinsicElements
regression (caused by missing `node_modules` in fresh worktrees)
rather than silently passing.
Root cause confirmed: `npm run lint` returns 0 errors after
`npm install`; tsconfig.json and @types/react are correct.
The regression only appears without node_modules.
Task: a2a_1778114702912_1ac758ea
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: install API deps for UI workflow
* fix: seed provider module targets before providers
* fix: stabilize UI final truth gate
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(roadmap): sync Hermes3D state with live baseline (H3D-CLAUDE-DOCS-PROOF) (#53)
Add Claude-authored docs companion and proof for the 20-Agent Completion
Contract Lane 18. Records the 5-commit shared baseline, 16-tab inventory
from routes.tsx, and the live S1/T1/V400 printer policy. README gains
pointers to the operator GUI roadmap and the contract handoff. ROADMAP.md
intentionally not edited because of an active codex-master Hermes lock.
Hermes evidence chain: PASS
Task ID: H3D-CLAUDE-DOCS-PROOF
hermes_run_gate: PASS
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(app-shell): finish resizable panels + density + Simple/Main parity (H3D-CLAUDE-APP-SHELL) (#54)
ResizablePane hardening:
- Escape during drag restores pre-drag width
- touchAction: none on the handle so drag works on touch devices
- Re-clamp persisted width when min/max bounds change at runtime
- SSR-safe localStorage write guard
Lane scope was bounded by Codex-master locks on AppShell, Sidebar, TopBar,
Panel, globals.css, tailwind.config.ts — those files were not contended.
DockModeToggle left unchanged: TopBar already owns the live Simple/Main
toggle via setUiMode and coupling DockModeToggle would break Phase 2 panel
docking semantics.
Hermes evidence chain: PASS
Task ID: H3D-CLAUDE-APP-SHELL
hermes_run_gate: PASS
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(e2e): add tab-specific Playwright specs (H3D-CLAUDE-PLAYWRIGHT) (#55)
Adds per-tab Playwright e2e specs for all 16 primary tabs and Roadmap,
each asserting truthful root mount, no forbidden mock/placeholder text
in production surfaces, and a clean console. Network calls are stubbed
at the GUI-API boundary; printers.spec.ts hard-aborts any request that
would reach live S1/T1/V400 operator IPs.
Hermes Task ID: H3D-CLAUDE-PLAYWRIGHT
Hermes evidence: ev_9d0e995e54bbac18
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(security): MCP boundary + prompt-injection + secret-redaction audit (H3D-CLAUDE-SECURITY-MCP) (#56)
Lane 19 of the Hermes3D 20-Agent Completion Contract. Adds READ-ONLY
behavioural tests over the in-house OWASP LLM-01 prompt-injection scanner
(commit 0c9b6d9), the secret-redaction surface in services/local_state.py
+ services/module_runtime.py + services/agent_runtime.py, the canonical
user-supplied-path validators in services/code_history.py, and the
MCP/tool-boundary policy gates that protect printers and the agent
runtime URL.
New files (lane-owned only):
- 03_implementation/tests/security/__init__.py
- 03_implementation/tests/security/conftest.py
- 03_implementation/tests/security/test_prompt_injection.py
- 03_implementation/tests/security/test_secret_redaction.py
- 03_implementation/tests/security/test_path_traversal.py
- 03_implementation/tests/security/test_mcp_boundary.py
- 03_implementation/proof/security/SECURITY_AUDIT_2026-05-06.json
- 03_implementation/docs/security/MCP_BOUNDARY_NOTES.md
Vectors covered (full list in SECURITY_AUDIT_2026-05-06.json):
- OWASP LLM-01 indirect injection, ChatML/Llama control tokens,
RCE-shaped tool-poisoning (curl|sh, wget|bash, iex/iwr), prompt-leak
variants, jailbreak personas (DAN, devmode, ignore-safety,
no-restrictions, pretend-unrestricted), and unicode-control no-crash
guarantees.
- LLM-02 (light): execute-following + base64 payload framing.
- LLM-06: AST scan over services/*.py rejects raw secret-shaped
literals (sk-, ghp_, AKIA, bearer, xoxb-) in source AND in any
logging emitter call site; pins module_runtime._redact_text on
every subprocess->output_head path; pins agent_runtime never logs
private_values / private_env() / env_value() return values.
- Path traversal: 8 explicit-reject vectors (../etc/passwd, drive
letters, null-byte injection, empty path), plus the documented
coercive cases (/etc/passwd and //attacker.example/share/x are
re-rooted into PROJECT_ROOT — informational, no escape possible).
- MCP boundary: build-plate-clearance gate, FLSUN S1 read-only lock,
trusted_runtime_url rejects non-private hosts / credentials /
query / fragment / wrong scheme / self-bridge ports 8765+8642,
scanner ships >=15 OWASP + >=10 in-house rules, fail_threshold
knob, redacted-text logging sink, secret-storage convention pinned
to G:\private\.env (outside repo).
Findings (logged, NOT silently fixed; surfaced via xfail strict=True
so they fail loudly when patched upstream):
- FINDING-INJ-1 (medium, owner = core/security ruleset lane):
LLM01-LEAK-VERBATIM regex misses reverse word order
`the prompt verbatim`. Suggested fix: anchor on `verbatim`
independent of word order or add LLM01-LEAK-VERBATIM-REV.
- FINDING-INJ-2 (medium, owner = core/security ruleset lane):
Zero-width-space (U+200B) injected in `ignore` bypasses
LLM01-IGN-PREV; `dump` is missing from leak alternation.
Suggested fix: pre-normalise zero-width / bidi control chars
before matching; extend LLM01-LEAK-SYSPROMPT verb alternation.
- FINDING-PATH-1 (low, informational, owner = Codex / code_history
lane): `_resolve_project_subpath` re-roots `/etc/passwd` and
`//attacker.example/share/x` into PROJECT_ROOT rather than
rejecting. SAFE (no escape; `relative_to(PROJECT_ROOT)` enforces
containment) but contract is coercive, not rejective.
Required gates: PASS
- python -m py_compile services/*.py routes/*.py: PASS
- scan_active_ui_no_fake.py: PASS
- pytest 03_implementation/tests/security/: 78 passed, 2 xfailed
- npm run lint: PASS
Hermes evidence: ev_cfb93a332dd6918a (ledger entry hash chain
extended). Lock owner: claude-security-mcp-19. No files outside
03_implementation/{tests,proof,docs}/security/ were modified.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(source-gen3d): real source+runtime verifiers for ComfyUI/TRELLIS/Hunyuan3D/TripoSR (H3D-CLAUDE-SOURCE-GEN3D) (#57)
Adds adapter_registry/scripts/tests for the five generative-3D providers
without performing any heavy operation:
* schemas: extend comfyui/trellis2/hunyuan3d/triposr/bambustudio_bridge
with source_repo, pip_package, weights_cache_dirs (all backward compatible).
* scripts/verify_gen3d.py: stdlib + subprocess only.
- git ls-remote --heads (no clone), 5s timeout.
- pip show <pkg> (no install), 5s timeout.
- Boolean cache-presence for ~/.cache/huggingface and similar.
- Bambu Studio: launcher executable presence only (no launch).
* proof/GEN3D_VERIFY_2026-05-06.json: 5/5 repos reachable;
Bambu Studio launcher present; comfyui/trellis2/hunyuan3d/triposr
honest "not installed" (no fabrication, no downloads).
* tests/source_lab/test_gen3d.py: pytest validates proof shape, policy
invariants, full provider coverage, and reachability honesty.
Hermes evidence chain: PASS
Task ID: a2a_1778106411818_946d5ec0
Lane: H3D-CLAUDE-SOURCE-GEN3D
hermes_run_gate: verify_gen3d, pytest test_gen3d, py_compile, scan_active_ui_no_fake
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(source-firmware): firmware toolchain proof gates, no-flash safety (H3D-CLAUDE-SOURCE-FIRMWARE) (#58)
- Add JSON schemas for Klipper, Marlin, RepRapFirmware, Prusa firmware sources
- Add JSON schemas for arm-none-eabi-gcc and avr-gcc toolchains
- Add verify_firmware.py: probes toolchain availability (--version only) and
firmware source reachability (git ls-remote only); NEVER flashes, NEVER
opens serial/USB to printer boards
- Add test_firmware.py: pytest suite asserting schema validity, no-flash policy,
verifier source integrity, and no-network proof generation
- Add FIRMWARE_VERIFY_2026-05-06.json: proof artifact (all 4 firmware sources
reachable; toolchains absent on this host — honestly recorded)
Lane: H3D-CLAUDE-SOURCE-FIRMWARE
Owner: claude-source-firmware-05
Hermes evidence chain: PASS
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(source-printfarm): read-only Moonraker/Klipper/OctoPrint verifiers (H3D-CLAUDE-SOURCE-PRINTFARM) (#59)
- verify_printfarm.py: HTTP GET-only probes for Moonraker (T1-a, T1-b, V400),
OctoPrint, Fluidd, Mainsail, FDM Monster, KlipperScreen, Printrun.
FLSUN S1 camera skipped per lane policy. Honest "unreachable" for all
localhost services (not running on this host). 3/3 Moonraker printers
reached; V400 version: v0.7.1-586-gbb526e0-dirty.
- test_printfarm.py: pytest suite asserting proof JSON shape, policy
invariants, GET-only constraint, S1 never-probed, and summary consistency.
- PRINTFARM_VERIFY_2026-05-06.json: proof artifact with live results.
- adapter_registry/schemas/moonraker_api.schema.json: JSON Schema for
read-only Moonraker HTTP adapter (GET-only, forbidden endpoints listed).
- adapter_registry/schemas/klipper_service.schema.json: JSON Schema for
Klipper service adapter (systemctl/moonraker-proxy, no G-code ever).
Hermes evidence chain: PASS
Task ID: H3D-CLAUDE-SOURCE-PRINTFARM
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(source-modelers): real verifiers for Blender/OpenSCAD/FreeCAD/CadQuery/build123d/trimesh (H3D-CLAUDE-SOURCE-MODELERS) (#60)
- 9 adapter schemas with real verify blocks (version_probe, install_check, runtime_check)
- scripts/verify_modelers.py: live CLI + pip-show probes, no fake/mock gates
- tests/source_lab/test_modelers.py: pytest contract validation for proof JSON
- proof/MODELERS_VERIFY_2026-05-06.json: honest results — found: blender, openscad, trimesh; not_found: freecad, cadquery, build123d
Lane: H3D-CLAUDE-SOURCE-MODELERS
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(artifacts): proof bundle index + artifact discovery API (H3D-CLAUDE-ARTIFACTS-PROOF) (#61)
- artifacts.py: add GET /api/artifacts/list (scans proof/ dir live, no hardcoded data)
and GET /api/artifacts/proof/{filename} (serves proof files with path-traversal guard)
- PROOF_MANIFEST_2026-05-06.json: real manifest of all 14 proof files in proof/
(generated by scanning directory, includes sizes, timestamps, lane IDs)
- Artifacts.tsx: add Proof Bundles panel calling /api/artifacts/list; displays
all proof files with View links; no mock data
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(learning-autopilot): truthful idle work kinds + real backend state (H3D-CLAUDE-LEARNING-AUTOPILOT) (#62)
- AutopilotConsole: remove hardcoded fake status values (Loop: on, Window: 8h, Risk: low)
that were not connected to any backend; replace with props-driven readyCount/totalChecks
that drive honest live/unavailable/blocked state display
- AutopilotTab (existing): already calls /api/autopilot/readiness + /api/autopilot/guardrails
for real backend state - no fake activation
- LearningTab (existing): all idle work kinds call real endpoints with honest blocked state:
createIdleCandidate → POST /api/learning/idle-workbench/candidates
runIdleCandidate → POST /api/learning/idle-workbench/candidates/{id}/run
requestIdleCandidateReview → POST /api/learning/idle-workbench/candidates/{id}/request-review
decideIdleCandidate → POST /api/learning/idle-workbench/candidates/{id}/decision
- Backend learning.py: run endpoint returns accepted:false + reason when runtime not configured
- Backend autopilot.py: next-gate returns 409 with failing check detail when not all ready
- Pre-existing TS7026 regression: 0 errors (lint clean)
- Python compile: learning.py OK, autopilot.py OK
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(source-slicers): real CLI verifiers for slicers (H3D-CLAUDE-SOURCE-SLICERS) (#63)
* feat(design): real CAD template gallery + provider health checks (H3D-CLAUDE-DESIGN) (#65)
- backend: add GET /api/design/templates — discovers templates from real
importable executor modules (hermes3d.core.design.*), reports
executor_available + missing_deps from live importlib checks
- backend: add GET /api/design/providers — probes OpenSCAD, Blender,
CadQuery, trimesh, manifold3d, FreeCAD via shutil.which + importlib;
no cached stubs, no fake version strings
- UI: Design.tsx pulls templates and providers from real backend endpoints;
template select populated from /api/design/templates (disabled if
executor unavailable); provider health panel shows live probe results;
template gallery shows preview-not-available for all templates (no
renderer wired); no hardcoded "Generated successfully" messages
- tests: add 04_testing/pytest/unit/test_design_providers.py — 18 tests
covering _discover_templates, _probe_providers, _probe_cli_provider,
_probe_python_provider; trimesh/manifold3d tests assert against live
importlib.util.find_spec to prevent divergence from reality
Pre-existing TS7026 errors in other tabs (not Design.tsx): noted in PR, not
fixed in this lane per cross-lane separation rules.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(observe): camera grid + S1 90deg + refresh reliability + V400 status (H3D-CLAUDE-OBSERVE) (#67)
- Backend: add GET /api/observe/status with per-camera health, response_ms, estimated_fps,
and read_only flag (S1 at 192.168.0.12 is flagged read-only; never receives control cmds)
- Backend: refactor _probe_camera into _probe_camera_timed for fps estimation;
update camera_health endpoint to return response_ms + estimated_fps
- Frontend types: add CameraStatus + ObserveStatusResponse interfaces to observe.ts
- Observe.tsx: exponential backoff retry on feed error (1s base → 30s max);
feedState gains 'reconnecting' state with spinner overlay instead of broken image;
auto-refresh interval selector (off / 3s / 5s / 10s / 30s) polls /api/observe/status;
online/offline summary badge in header; Refresh all button triggers both feed + status fetch;
V400 per-card online/offline chip + fps indicator from status API;
S1 defaults to 90deg rotation (backend + defaultViewSettings already enforced)
- ObserveConsole.tsx: replace hardcoded mock camera list with live /api/observe/status polling
every 5s; shows read_only badge on S1, fps estimate per camera, online/offline with ping ms
Camera safety: S1 (192.168.0.12) is camera/read-only throughout; no move/upload/print/test
commands are issued from Observe tab or status endpoint.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): policy-gated repair/retry/rollback + proof state (H3D-CLAUDE-JOBS) (#68)
- Add _check_printer_policy() to jobs.py enforcing three ordered gates:
1. S1 hard lock (192.168.0.12 / flsun-s1 always rejected, HTTP 423)
2. PRINTER_WRITE_DENIED: printer must be write_enabled or in WRITE_ALLOWED_PRINTERS (HTTP 423)
3. PRINTER_IDLE gate: printer state must be standby/complete/ready/error before retry/repair/rollback (HTTP 409)
- apply_repair, retry_job, rollback_job all call _check_printer_policy() before mutating any state
- propose_repair calls check_s1_lock() (read-only planning step, no printer movement)
- Every policy block records a proof event in proof_events table with printer_id, job_id, reason
- Jobs.tsx already correct: real endpoints, state machine, proof event IDs displayed — no fake messages
- Add 04_testing/pytest/unit/test_jobs_policy.py: 37 tests covering S1 lock, read-only policy, PRINTER_IDLE gate, no-printer pass-through, write-enabled idle pass-through, proof event DB writes
NEVER sends job commands to moving printers. S1 (192.168.0.12) never a job target.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(gen3d): real provider readiness + proof-backed local templates (H3D-CLAUDE-GEN3D) (#70)
- backend: add GET /api/gen3d/providers — reads Lane 04 GEN3D_VERIFY_2026-05-06.json
proof + live port probe for ComfyUI; returns installed/repo_reachable/weights_present
for comfyui, trellis2, hunyuan3d, triposr, bambustudio_bridge; no fake readiness
- backend: add GET /api/gen3d/templates — discovers local templates (calibration_cube via
trimesh, no provider needed) + provider-backed templates from adapter_registry schemas;
schema_present field reflects real file existence
- UI: provider status panel now shows 3D generation provider readiness (from
/api/gen3d/providers) with readiness badges sourced from Lane 04 proof data
- UI: local template gallery (from /api/gen3d/templates) — cards show source, outputs,
required provider; selecting provider-backed template with unavailable provider shows
"Provider not available" on Generate with a proof event emitted
- tests: add test_gen3d_routes.py with 14 unit tests covering both new endpoints
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(source-ui): SourceOS CLI readiness + proof panel + no-cutoff layout (H3D-CLAUDE-SOURCE-UI) (#66)
- Add CliReadinessPanel component: collapsible section showing CLI readiness
for all 5 tool categories (slicers, modelers, print_farm, firmware, gen3d)
with per-key-tool status badges (Verified CLI / Detected / Source Ready /
Not Installed / Unavailable). Data comes from /api/sources/readiness.
- Add ProofArtifactPanel component: collapsible section with links to
/api/artifacts and per-category artifact queries, plus proof file listing.
- CliReadinessPanel and ProofArtifactPanel use overflow-y: auto with maxHeight
to ensure no content cutoff — all content is scrollable.
- Create 03_implementation/src/hermes3d/api/routes/source_os.py:
GET /api/sources/readiness reads proof JSON files (LOCAL_TOOLING_AUDIT,
SOURCE_APP_CLI_AGENT_READINESS_AUDIT, SOURCE_APP_CLI_SURFACE_AUDIT) and
returns aggregated readiness per category with key tool details.
- Wire source_os router into hermes3d/api/app.py.
- No hardcoded readiness states — all from proof JSON files.
- tsc --noEmit: PASS (zero errors in owned files; pre-existing TS7026 regression
in other src/*.tsx files predates this contract).
- py_compile source_os.py: PASS.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(settings-plugins): update center + provider health + failsafe rollback (H3D-CLAUDE-SETTINGS-PLUGINS) (#69)
- Add GET /api/settings/update-center: real component versions, Velopack readiness, live provider probes, rollback availability
- Add POST /api/settings/update-center/rollback/{component}: surfaces rollback for proof-gated flow
- Register update_center router in app.py
- New UpdateCenterSubtab.tsx: live update center with failsafe rollback cards
- New PluginRollbackPanel.tsx: per-plugin health + deactivate/rollback action
- SettingsPage.tsx: add Update Center subtab wired to UpdateCenterSubtab
- AboutSubtab.tsx: fetch real versions from backend, removed hardcoded VERSION constant
Pre-existing TS errors in other files not introduced here. tsc passes clean for all touched files.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(voice): transcript history + playback controls + proof review (H3D-CLAUDE-VOICE) (#64)
- Backend: add GET /api/voice/transcripts, GET /api/voice/recordings/{id},
GET /api/voice/proof-events to voice.py; recordings served as binary
audio from proof_events table; no API key in any URL
- Types: add VoiceTranscript and VoiceProofEvent to voice.ts
- Adapters: add getVoiceTranscripts, getVoiceProofEvents, getVoiceRecordingUrl
to AdapterAPI interface + live implementations + parse helpers
- UI: Voice.tsx gains three-tab layout (Voice Browser / Transcript History /
Proof Review); playback routed through backend only (new Audio(backendUrl)),
no device access from frontend; honest empty states when no data yet
Gates: python -m py_compile OK; tsc --noEmit 0 errors
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(printers): onboarding wizard + Moonraker probe + S1 camera-only lock (H3D-CLAUDE-PRINTERS) (#71)
- Add 5-step printer onboarding wizard to PrintersTab:
Step 1: Enter IP + connection type (Moonraker/OctoPrint/direct)
Step 2: Auto-probe via GET /api/printers/probe (read-only, shows version/firmware/bed size)
Step 3: Set camera URL with MJPEG validation
Step 4: Confirm + save profile with write-enable toggle
Step 5: Done / refresh fleet
- S1 (192.168.0.12) is LOCKED in the wizard: shows 'Camera only — cannot add as
print target' before any network call is made; frontend enforces CAMERA_ONLY_IPS set
- Add GET /api/printers/probe backend endpoint:
Read-only: calls only GET /server/info and optional /printer/objects/query
Never sends GCode, commands, or mutations
Returns: Moonraker version, klippy_state, bed size from fleet profile
- Add POST /api/printers/validate-camera backend endpoint:
Read-only: HEAD request only, checks Content-Type for multipart/x-mixed-replace
Returns: {ok, content_type, is_mjpeg, http_status}
- Add CAMERA_ONLY_IPS frozenset constant in printers.py (single source of truth):
Any attempt to add 192.168.0.12 as a print target returns 403 CAMERA_ONLY_IP
Covers: probe endpoint, onboard URL validation, printer ID validation
- Add test_printer_policy.py (16 tests, all passing):
- S1 IP blocked in onboard URL validation (403 CAMERA_ONLY_IP)
- S1 aliases blocked in printer ID validation (423)
- Probe endpoint returns 403 for S1 IP
- Probe is read-only: send_gcode/upload_gcode/start_print never called
- Camera validate uses HEAD request only
- MJPEG detection verified
- TestClient route integration tests
- TypeScript: tsc --noEmit passes cleanly (0 errors in owned files)
- Python: py_compile passes for printers.py and test_printer_policy.py
- Pre-existing TS7026 errors in other src/*.tsx files are unrelated to this lane
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(integration): 20-agent completion integration report (H3D-CLAUDE-FINAL-INTEGRATOR) (#72)
All 19 lane PRs (#53-#71) are OPEN/MERGEABLE with CodeRabbit SUCCESS and
Hermes evidence chain PASS. Two cross-lane file conflicts identified:
- app.py: PRs #66 + #69 both add a router (additive, UNION merge)
- adapters.ts / adapters.live.ts: PRs #64 + #71 both add methods (additive, UNION merge)
Merge order: Tier-1 (15 PRs in parallel) → Tier-2 (#66→#69) → Tier-3 (#64→#71).
Pre-existing JSX TS7026/TS7006 regression (~57 files) flagged as HIGH-priority fix-PR
needed before release.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* audit(runtime): proof files + verifier scripts + route truth verification (#74)
Verifies all 6 proof JSON files are real (not hand-crafted), all 4 verifier
scripts use genuine subprocess/filesystem probes, and all 7 API routes have
real implementations. All syntax checks pass. No blockers found.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* audit(merge): PR base + conflict cluster + silent drop verification (H3D-CLAUDE-POLISH-MERGE-2026-05-06) (#75)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* audit(security): secret scan + path traversal + shell audit (H3D-CLAUDE-POLISH-AGENT-MCP-PROOF-2026-05-06) (#76)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* audit(safety): S1 lock + printer policy + GCode scan verification (#77)
53/53 policy tests pass. S1 (192.168.0.12) blocked before every network call.
Zero GCode keywords in probe/read routes. Zero bypass paths found. Camera controls
are CSS-only display transforms with no hardware commands.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* audit(docs): PR body completeness + ROADMAP truth + merge plan verification (H3D-CLAUDE-POLISH-RELEASE-DOCS-2026-05-06) (#78)
- Audited all 20 PR bodies (#53-#72): all have evidence chain, task ID, and gates
- PR #53 missing formal files table (prose description present); PR #64 minimal body
- TS7026 blocker documented in PR #72; absent from ROADMAP.md (codex-master locked)
- README "77 of 79" claim is stale relative to feature branch (update post-merge)
- Merge Tier 1/2/3 structure is correct; PR #72 needs explicit Tier 4 slot in plan
- No PRs accidentally merged; all 20 lane PRs remain open
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* audit(nofake-ui): 0 violations — no-fake scan + 33 buttons wired + 0 lane TS errors (H3D-CLAUDE-POLISH-NOFAKE-UI-2026-05-06) (#79)
* docs(handoff): final Codex takeover bundle — 9 audit/merge/lock files (#81)
Closes the Claude 20-agent + 6-audit-agent run. Contains:
00_EXECUTIVE_TAKEOVER_SUMMARY.md — 1-page status for Codex
01_PR_MERGE_MATRIX.md — exact tier merge order for #53-#80
02_OPEN_BLOCKERS_AND_FIX_QUEUE.md — 0 code blockers, 4 low/info doc gaps
03_LOCKS_WORKTREES_AND_BRANCHES.md — 28 Claude locks released, 28 worktrees
04_RUNTIME_TRUTH_AND_NO_FAKE_AUDIT.md — Audit 2+3: 0 fake violations
05_PRINTER_SAFETY_AND_PHYSICAL_IO_AUDIT.md — Audit 4: S1 camera-only PASS
06_SECURITY_MCP_AND_AGENT_ACCESS_AUDIT.md — Audit 5: no traversal/secret leaks
07_ARCHITECTURE_AND_FLOW_DIAGRAMS.md — Mermaid diagrams for all flows
08_FINAL_CLAUDE_RELEASE_NOTE.md — final PR list + lock state + Codex next steps
All 28 Claude-owned Hermes locks released.
All 20 lane PRs (#53-#72) and 6 audit PRs (#74-#79) open CLEAN.
TS7026 fix PR #80 open (CI running).
Hermes task: a2a_1778115796454_685e7b14
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ui): clear post-merge npm audit vulnerabilities (#82)
* fix(ui): clear npm audit vulnerabilities
* fix(ui): clean post-merge browser gates
* fix: align observe refresh button contract
* [codex] add MCP-locked Hermes Agent code operator (#73)
* feat(agents): add MCP-locked code operator lane
* docs(handoff): add Claude final audit takeover contract
* fix(agents): harden code operator lane
* docs(handoff): Hermes3D OS folder index 2026-05-07 — 86 markdowns w/ inline SVG (#86)
Comprehensive index of every Hermes3D OS folder in G:\Github\ modified
between 2026-04-27 and 2026-05-07. Authored by 13 parallel sub-agents
under task a2a_1778147261453_661b606f.
Structure (12 categories, 60 included folders, 7 excluded):
00_INDEX.md -- master nav + topology SVG
01_TAXONOMY.md -- classification rules
02_EXCLUSIONS.md -- 7 folders intentionally excluded + reasons
apps-vendored/ -- 7 vendored apps (~1.08 GB) + README
core-repos/ -- 5 core H3D repos + README
agent-infra/ -- 5 hermes-agent / MCP infra + README
hp-protocol/ -- 9 HP P0/P1 hardening folders + README
hermesproof/ -- 6 HermesProof component sandboxes + README
source-os-60-apps/ -- canonical 60-app registry + treemap SVG
h3dos-wire-tasks/ -- 18 single-button UI wire lanes + README
h3dos-codex-tasks/ -- 5 Codex app integration lanes + README
merge-prs/ -- 4 cascade-merge worktrees + README
h3d-enhancements/ -- 7 H3D enhancement branches + README
worktree-collections/ -- 3 umbrellas (49 sub-worktrees) + README
research/ -- _research scratchpad + README
Each per-folder markdown includes: H1 title, purpose, status,
branch+commit, key files, relationships, and inline hand-written
SVG (400-900 px). Category READMEs add master inventory tables and
larger SVGs (700-900 px).
Excluded (7): kilocode-Azure2, contract-kit-v17 (3 variants),
TRELLIS.2, Agentic-Modeler, _repo_rescue_evidence -- documented
in 02_EXCLUSIONS.md with reasoning.
Hermes evidence chain: PASS
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(queue): recover closed stacked PR work (#105)
* feat(agents): add MCP-locked code operator lane
* docs(handoff): add Claude final audit takeover contract
* fix(agents): harden code operator lane
* feat(agents): add proof-gated git shipping lane
* feat(agents): add provider team assignment lane
* feat(agents): add provider execution artifacts
* feat(source-os): add runner contract matrix
* feat(source-os): register python cad verifier family
* feat(source-os): correct slicer runner truth
* feat(source-os): add print farm health verifiers
* feat(source-os): add service web health verifiers
* feat(source-os): add safe service start-runner preflights
* feat(source-os): supervise service runner starts
* test(unit): remove live fleet timeout from offline tests
* feat(source-os): add firmware source inventory verifiers
* feat(accel): add rust metadata proof worker
* feat(source): add read-only runner smoke contracts
* feat(source): add executable path runner smoke
* feat(source): add python import repair preflights
* feat(source): add slicer cli config preflights
* feat(source): add npm package metadata preflight
* docs(agents): define e2e proof plan
* feat(agents): add e2e workbench
* feat(agents): add provider smoke and reviewed ship lane (#104)
* feat(agents): add provider smoke and reviewed ship lane
* fix(agents): prove live runtime freshness
* feat(agents): add cli runner contracts
* fix(agents): require live provider smoke proof
* docs(handoff): Claude 20+ agent E2E completion intelligence bundle 2026-05-08 (#106)
Read-only intelligence sweep produced per PR 104's Claude 20+ Agent E2E
Completion Intelligence Contract. 12 markdown deliverables under
03_implementation/docs/handoffs/claude-e2e-intelligence-2026-05-08/
covering: executive map, G:/Github folder ecosystem audit, stale
code/branch map, Hermes Agent runtime gap map, Source OS 60-app
completion map, tab-by-tab UI no-fake audit, env-key/runtime config map,
test gates + proof matrix, PR + merge queue, Codex next 50 tasks, 6
Mermaid diagrams, and final Claude note.
Live truth captured at 2026-05-08 17:25Z from API on branch
codex/provider-smoke-workbench commit 43d8205: 220 routes, all 10 Agent
Workbench routes present, 60 Source OS apps (7 agent_cli_ready, 24
runner_gaps), 81 active UI files clean (no-fake scan PASS), 25 open PRs
all CLEAN/CodeRabbit-SUCCESS. Hard blocker: MiniMax + DeepSeek HTTP 401
on G:/private/.env keys (Tier 0 user action; Codex chain not blocked).
No source code edited. No PRs merged. No Codex-owned locks released. 12
hermes3d-locks acquired by claude-e2e-intel-aggregator (taskId
claude-e2e-intel-2026-05-08) for the markdown bundle; released after PR
open per contract.
Hermes evidence chain: kickoff ev_b6e233d4ac466056
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(agents): prove provider env aliases (#107)
* docs(handoff): prepare Claude 24-agent completion contract (#108)
* proof(I14): update no-fake sweep 2026-05-08 — 81 files, PASS (#116)
Active UI no-fake scan re-run on 2026-05-08:
- 81 production files walked from App.tsx entry point
- 0 findings (no mock/fake/simulated markers in string literals)
- No data/mock imports in active graph
- 15 orphaned/unwalked files separately verified clean
- scan_active_ui_no_fake.py requires no changes
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(I8): printer safety — S1 camera-lock tests, T1/V400 policy gates (#111)
Adds 25 new test cases to test_printer_policy.py closing the critical safety
gap where S1 (192.168.0.12) action endpoints (move, test, upload, upload-gcode)
had no direct hard-lock assertions. New TestS1ActionHardLock class proves 423
PRINTER_LOCKED fires before any MoonrakerClient I/O for all four action routes,
across all S1 aliases. TestT1V400PolicyGates confirms write-allowed printers are
not misclassified as S1 and pass the lock gate. 78/78 tests pass.
Task: H3D-CLAUDE24-I8-PRINTER-SAFETY
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(I4): add runner_family to all 60 runner-contracts + blocked_reason for BLOCKED rows (#119)
- Add _contract_runner_family() mapping runner_status → valid family string
- Add runner_family field to module_runner_contract() return dict (was absent,
causing all 60 /runner-contracts rows to have FIELD_MISSING)
- Fix blocked_reason for slic3r and superslicer (runner_status=blocked):
previously suppressed by cli_install_config_available=True condition; now
always set when runner_status==blocked regardless of preflight runner
- Valid families emitted: agent_cli_ready, read_only_runner, executable_path,
python_import_repair, cli_install_config, npm_package_preflight,
desktop_app_runner_gap, gpu_worker_runner_gap, runtime_repair_required,
source_reference_only, blocked, metadata_ready_needs_runner
- 113 pytest tests pass; only locked file modified
Task: H3D-CLAUDE24-I4-SOURCEOS-CORE
Hermes evidence chain: PASS
Gates run: python -m py_compile (both files), pytest 113 passed
Rows fixed (null→known runner_family): 60
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I1): provider endpoint/model config audit — MiniMax+DeepSeek smoke (#112)
Audit confirmed both providers have correct code configuration:
- MiniMax: /v1/chat/completions, Bearer auth, MiniMax-M2.7 — all correct
- DeepSeek: /chat/completions, Bearer auth, deepseek-v4-pro — all correct
HTTP 401 on both is a pure API key issue (invalid/expired keys in G:\private\.env).
Added inline comments to PROVIDER_DEFAULT_BASE_URLS documenting the verified
endpoint/auth/model contract and the exact user action needed to resolve 401s.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(I2): wire E2E code loop — patch-apply, gate-run, branch-commit-pr chain (#118)
- audit confirmed: apply_reviewed_patch_proposal, run_mcp_gate,
git_commit_owned_files, git_push_current_branch, git_open_pull_request,
restore_snapshot all fully implemented (no stubs)
- wiring gap found and fixed: no GET /e2e/jobs endpoint existed to list
job states — added list_e2e_jobs() to code_history.py and the
GET /api/code-operator/e2e/jobs route to code_operator.py
- new GET route queries proof_events for code_e2e/code_patch/code_git
event types and returns job state legend for E2E loop operators
- expanded test_code_operator_routes_are_registered to assert all 7
E2E chain routes are wired: apply-reviewed, gates/run, git/branch,
git/commit-owned, git/push, git/pr, e2e/jobs GET
- added test_list_e2e_jobs_returns_proof_events and
test_list_e2e_jobs_route_returns_200 — 92 tests pass (was 90)
- py_compile passes on both locked files
- provider 401 remains user-action only: I1 audit confirmed HTTP 401
is a pure invalid API key issue; no provider HTTP code touched
Task: H3D-CLAUDE24-I2-E2E-CODE-LOOP
Hermes evidence chain: PASS
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(I3): OpenCode/OpenHands sandbox readiness + GET preflight route (#121)
* feat(I3): OpenCode/OpenHands sandbox readiness + GET preflight route
- Add opencode_openhands_sandbox_readiness() in code_history.py returning
the I3-spec shape: opencode_detected, opencode_version, openhands_detected,
openhands_image, sandbox_network_mode (always "none"), denied_paths, ready
- Add preflight_code_cli_runner_get() for non-mutating --version dry-run
(GET variant, no task claim required); returns stdout, exit_code, elapsed_ms
- Wire GET /api/code-operator/sandbox/readiness to new function (replaces
Docker-based response with OpenCode/OpenHands detection schema)
- Add GET /api/code-operator/cli-runners/preflight?runner_id=opencode|openhands
- Add SandboxReadiness panel to Agents.tsx with real detected/not-detected
badges (data-testid=sandbox-readiness-panel), Refresh button, network mode
and denied-paths display — no fake states
- Evidence: ev_040fad5fbd843c38 (opencode v1.4.3-hermes3d detected, exit_code=0)
- 38 unit tests green; task H3D-CLAUDE24-I3-OPENCODE-OPENHANDS released
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I3): wire setSandboxBusy into Refresh onClick — resolve TS6133
Layer D2 UI-Final failed because setSandboxBusy was declared but its
setter was never invoked (TS6133). Wire it correctly: setSandboxBusy(true)
before the fetch, .finally(() => setSandboxBusy(false)) after, so the
Refresh button correctly shows "checking" during load and CI passes.
Evidence: ev_ffa9a8c3e3bd4a40 | Task: H3D-A1-PR121-FIX
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(I7): firmware source inventory probes — read-only git describe, source_reference_only contract (#120)
- Add FIRMWARE_SOURCE_PATHS registry mapping all 6 firmware module IDs to
their actual source checkouts under Hermes3D-OS/source-lab/sources/
- Add _git_describe(): read-only subprocess.run(git describe --tags --always)
with timeout=5s; returns None on any error — no flash/compile/serial
- Add probe_firmware_source_inventory(module_id): returns source_found,
version_tag, runner_status=source_reference_only, agent_executable=False
- Add probe_all_firmware_sources(): aggregates all 6 modules in one call
- Update BUILTIN_RUNTIME_PROBES firmware entries: path fields now point to
confirmed source checkouts; kind changed to firmware_source_inventory
- Add 04_testing/pytest/unit/test_firmware_farm_probes.py — 49 tests:
registry coverage, contract template, _git_describe (mocked), per-module
parametrized happy/absent paths, safety constraint enforcement tests
- Live probe result (evidence ev_842d77f8663ea2ee):
firmware_klipper=293e1e9, marlin=03cc75f, prusa_firmware=f3e0dfd,
reprapfirmware=f4297ad, repetier_firmware=7cb3741, smoothieware=620e162
- ABSOLUTE CONSTRAINTS: no avrdude/dfu-util/openocd/esptool, no serial port,
no make/cmake/platformio, S1 not probed, T1/V400 source-only
Hermes evidence chain: PASS
Task ID: H3D-CLAUDE24-I7-FIRMWARE-FARM
Evidence ID: ev_842d77f8663ea2ee
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(I6): service/web-app health probes + service_web_health_runner status (#122)
Add seven named read-only HTTP probe functions (probe_fluidd, probe_mainsail,
probe_octoprint, probe_fdm_monster, probe_octofarm, probe_manyfold,
probe_comfyui) plus a probe_service_web_health dispatcher. Each probe uses
GET with a 3-second timeout, never POSTs, never mutates, and is blocked with
reason=no_configured_url when the env var is absent.
Update _runner_status to return service_web_health_runner (replacing the
generic readonly_api_ready) for local_http_health verifier kind, and add
service_web_health_runner_contract to _required_verifier_family.
Add 74-test suite in test_module_runtime.py covering: dispatcher routing,
blocked-when-no-url, non-local-URL guard, HTTP 200 happy path (mocked),
connection-error handling, 4xx handling, runner-contract status assertions,
and GET-only method verification. Update pre-existing test in
test_source_runtime_contracts.py to reflect the new runner_status value.
All 226 unit tests pass (74 new, 116 combined with existing module tests).
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I5): slicer/modeler CLI probes — PATH detection, --version proof, exact blocked reasons (#123)
* fix(I4): add runner_family to all 60 runner-contracts + blocked_reason for BLOCKED rows
- Add _contract_runner_family() mapping runner_status → valid family string
- Add runner_family field to module_runner_contract() return dict (was absent,
causing all 60 /runner-contracts rows to have FIELD_MISSING)
- Fix blocked_reason for slic3r and superslicer (runner_status=blocked):
previously suppressed by cli_install_config_available=True condition; now
always set when runner_status==blocked regardless of preflight runner
- Valid families emitted: agent_cli_ready, read_only_runner, executable_path,
python_import_repair, cli_install_config, npm_package_preflight,
desktop_app_runner_gap, gpu_worker_runner_gap, runtime_repair_required,
source_reference_only, blocked, metadata_ready_needs_runner
- 113 pytest tests pass; only locked file modified
Task: H3D-CLAUDE24-I4-SOURCEOS-CORE
Hermes evidence chain: PASS
Gates run: python -m py_compile (both files), pytest 113 passed
Rows fixed (null→known runner_family): 60
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I5): slicer/modeler CLI probes — PATH detection, --version proof, exact blocked reasons
Adds probe_slicer_cli() and probe_modeler_import() to module_runtime.py.
Non-mutating: --version/help only, no STL sent, no firmware flashed.
Detected (on this machine):
Slicers: PrusaSlicer 2.9.5, OrcaSlicer, FLSUN Slicer 2.0.4, CuraEngine 5.12.1, BambuStudio
Modelers: Blender 5.1.1, OpenSCAD 2021.01, trimesh 4.12.1, pymeshlab
Blocked (exact path tried recorded):
Slicers: SuperSlicer (not at C:/Program Files/SuperSlicer/), Slic3r (not installed)
Modelers: FreeCAD (FreeCADCmd not at standard paths), cadquery/build123d/numpy-stl/open3d (not importable), truck (source-inventory only)
Adds SLICER_MODULE_IDS, MODELER_PYTHON_IMPORT_IDS, MODELER_SOURCE_INVENTORY_IDS constants.
Adds _find_slicer_executable() with canonical + alt + PATH search.
Handles PrusaSlicer/OrcaSlicer/BambuStudio/FLSUN nonzero --version exit codes.
Tests: 43 new slicer/modeler probe tests + 42 existing contract tests = 85 total, all green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I10): reduce polling lag, fix sidebar overflow, layout fixes (#110)
- AppShell: remove lg:overflow-hidden on main in dashboard mode to prevent panel cutoff on large viewports (overflow-auto retained throughout)
- Sidebar: wrap AgentChatMirror in min-h-0 shrink container so tall chat panel no longer displaces nav items off-screen
- TopBar: fix stale data — was fetch-on-mount only; add 10 000 ms setInterval refresh for system snapshot, notifications, and proof bundle (non-critical display data)
- globals.css: no changes needed (font-size 13px and dashboard-grid overflow-hidden are intentional)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I11): SourceOS 60-row rendering, real API wiring, panel overflow (#114)
- Fetch /api/modules/runtime/runner-contracts on mount + after Verify All / Setup Queue actions
- Map runner_status (runner_family) per module_id into a lookup dict
- ModuleList: display runner_family badge for each of the 60 rows using real runner_status from contracts endpoint
- AppDetailPanel: add runner_family header pill + RunnerContract InfoBox showing runner_status, required_verifier_family, safe_actions, acceptance_gate, and blocked_reason
- Pass runnerContract down to AppDetailPanel and refresh it in onRefresh callback
- All 60 rows rendered without slice/limit (confirmed via /api/modules count:60)
- Controls (Verify, Setup Plan, Backup, Rollback) already wired to real API — confirmed no fake handlers
- Panel overflow: AppDetailPanel section has overflow-auto in flex container with min-h-0
scan_active_ui_no_fake: 81 production files scanned, 0 findings
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(I13): print workflow — remove fake job states, policy-gate print actions (#113)
Dashboard: rename PIPELINE_STAGES to PIPELINE_STAGE_ICONS and remove the
hardcoded status:'complete'/'active' fields from the lookup table. Those
fields were dead code (PipelinePanel always derives status from live API
stage data); keeping them risked a developer treating them as truth.
Autopilot: remove EXPECTED_READINESS_CHECKS=16 magic constant. The gate
'allReady' was permanently blocked unless the backend returned exactly 16
checks — even if every returned check passed. Now allReady is true when
checks.length > 0 && all returned checks are ready (API is source of
truth). Added a "loading…" label and empty-state message while the API
response is pending so the UI never shows 0/0 as a misleading ready count.
Jobs: remove the 'counts' useMemo that injected 0 into every non-active
filter tab badge. Showing "Queued 0 | Done 0 | Failed 0" without fetching
those counts is a fake/misleading value. Now only the active filter shows
a live count; inactive filter tabs show no count badge.
Printers: no fake states found — all print actions await real API
confirmation before updating UI, and S1 policy block is correctly enforced.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(observe): real health probing in /cameras, remove fake events, fix initial feed state (#115)
- observe.py /api/observe/cameras: replaced static _configured_camera_state()
(always "configured") with a real _probe_camera_timed() call per camera so
health reflects actual connectivity, not just URL presence.
- Observe.tsx initialFeedState: cameras with health="unreachable" now start in
"error" state instead of "loading", preventing endless "CONNECTING" badge on
known-dead feeds.
- ObserveConsole.tsx: removed hardcoded fake EVENTS strings; events panel now
derives per-camera status lines from the real /api/observe/status response.
Polling interval documented (STATUS_POLL_INTERVAL_MS = 5000ms >= 3000ms).
Task: H3D-CLAUDE24-I9-OBSERVE-CAMERA
Hermes evidence chain: PASS
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(I12): agent chat blocked state, voice text+audio+mute, learning real states (#117)
- AgentChatMirror: extract real blocked reason from response body (HTTP 401
from MiniMax/DeepSeek now shows the provider error text, not just status code)
- AgentChatMirror: add explicit 'Providers blocked' banner in chat history
when agent roster is empty, with action text for G:\private\.env config
- Voice.tsx: add mute button to TTS preview (Voice Browser fine-tuning panel)
and transcript playback — muting suppresses audio but ALWAYS shows text
- Voice.tsx: text transcript displayed in all states; muted state explicitly
shown with amber indicator so user knows audio is off but text remains visible
Voice API probe: GET /api/voice/status → 404 (route not registered in backend);
GET /api/voice/providers → Azure Speech READY (configured, region=westus).
TTS routes through backend /api/voice/preview (confirmed base64 response).
Learning: real API calls only, blockers shown with real reasons (confirmed live).
No-fake scan: PASS (81 production files, no mock/fake/simulated UX markers).
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(provider): align MiniMax and DeepSeek runtime adapters (#124)
* docs(handoff): tighten Hermes runtime finish contract
* docs(sweep): PR #125 control sweep handoff + runtime finish report
- HERMES_RUNTIME_FINISH_REPORT.md: 10-agent audit results, merge
matrix, provider BLOCKED verdict (HTTP 401 both providers)
- PR125_CONTROL_SWEEP_HANDOFF_2026-05-09.md: full PR #125 sweep —
A1-A10 audit results, zombie lock recovery, secret safety PASS,
printer safety PASS, exact env key fixes required, next actions
Task: H3D-PR125-SWEEP-DOCS | Evidence: ev_dbf23c31c04af4ca, ev_a736131a4b0d8c6e
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(provider): align MiniMax and DeepSeek runtime adapters
- prefer MiniMax highspeed token-plan aliases and keep Max-Highspeed model routing explicit
- update MiniMax gateway to use MiniMax-M2.7-highspeed and max_completion_tokens
- update DeepSeek gateway/tests to use deepseek-v4-pro reasoning payload
- allow minimax/deepseek in llm policy and refresh provider rescue handoff docs
- keep provider smoke redacted; MiniMax now selects token-plan env and returns 429 insufficient_balance, DeepSeek remains 401
* docs(rescue): provider rescue blocker proof — adapters correct, blockers user-side
PR #124 provider completion sweep. Wave 1-3 audit:
- MiniMax adapter (gateways/providers/minimax.py): CORRECT per official docs.
Reaches api.minimax.io. HTTP 429 insufficient_balance (1008) is
provider-side billing/quota, NOT code, NOT auth.
- DeepSeek adapter (gateways/providers/deepseek.py): CORRECT per official
docs. Posts to api.deepseek.com/chat/completions with thinking +
reasoning_effort for v4-pro. HTTP 401 = "wrong API key" per
api-docs.deepseek.com/quick_start/error_codes (single documented cause).
No code fix needed. Both blockers are out-of-repo user actions:
1. MiniMax: top up Token Plan balance / OAuth portal auth at platform.minimax.io
2. DeepSeek: rotate DEEPSEEK_API_KEY in G:/private/.env
Hermes Agent loop remains BLOCKED until both providers return accepted:true.
Evidence: ev_cffabca307652c21 (minimax), ev_bdec2f02c01c17ec (deepseek),
ev_491fe9d07426cab4 (adapter audit).
Task: H3D-CLAUDE-PROVIDER-COMPLETION.
No private values exposed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(code-operator): expose redacted CLI provider env contract
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(agent): tighten control gates (#125)
* docs(rescue): mark blocker proof SUPERSEDED — providers now PASS (#132)
First proof-gated Hermes Agent coding loop. The full chain ran end-to-end
including a real recovery cycle:
MiniMax build (artifact 08c8dce66b3a4a589572cee225f2b428)
-> DeepSeek review v1 BLOCKED_ON_INSUFFICIENT_EVIDENCE
-> v1 proposal 8365f7833f10... DeepSeek APPROVE ev_675dcddbd474c55d
-> apply -> git-diff-check FAIL on trailing whitespace from ` ` line breaks
-> rollback to snapshot 6f478adcf452 (proof 245d7fd376fc)
-> v2 proposal f07e6af14f5f authored without trailing whitespace
-> DeepSeek APPROVE v2 ev_59947bb44bf1715a
-> apply -> git-diff-check PASS gate_git-diff-check_1778295564288
Provider smoke evidence baked into the SUPERSEDED block text:
minimax ev_4a52d9b1336ca9f2 HTTP 200 MiniMax-M2.7-highspeed
deepseek ev_e708071cb269f170 HTTP 200 deepseek-v4-pro
No private values exposed. Same-owner MCP locks throughout.
Task: H3D-FIRSTLOOP-001-SUPERSEDE
Hermes evidence: f07e6af14f5f4db3972fdc1bb336bd35, ev_59947bb44bf1715a, ev_675dcddbd474c55d, ev_4a52d9b1336ca9f2, ev_e708071cb269f170, ev_a2780d9832e5567a, ev_95e16427ce056505, ev_69e00f87178d6f9c
* feat(recovery): Hermes Agent Recovery Controller v1 (lean ledger) (#133)
First lean v1 of the Hermes Agent Recovery Controller, born from the
recovery cycles in PR #126. Backend ledger ONLY: no UI, no autonomous
apply, no file mutation by the controller. Future-proof v1.5 schema
fields included so the upcoming Hermes Agent Task Monitor UI can read
rich state without backend refactor.
What ships:
- code_history.py: RECOVERY_FAILURE_CLASSES (9), RECOVERY_OUTCOME_STATUSES
(3), RECOVERY_FAILED_STEP_TYPES (10), RECOVERY_RECOMMENDED_ACTIONS (8),
RECOVERY_REDACTION_STATUSES (3), RECOVERY_WORKER_OUTPUT_STATUSES (6),
RECOVERY_AGENT_STACK_VALUES (8), _RECOVERY_LEDGER_PATH, plus
record_step_failure(), mark_recovery_outcome(), list_recovery_attempts().
Adds `import secrets` and `from hermes3d.gateways.redaction import
redact_text` to imports.
- code_operator.py: RecoveryRecordFailureRequest, RecoveryMarkOutcomeRequest
StrictBody models + 3 routes: POST /recovery/record-failure, POST
/recovery/mark-outcome, GET /recovery/state.
- test_code_operator.py: 7 lean v1 tests covering record/reject/redact/
mark/state via TestClient with unique uuid4 task_ids.
- docs/handoffs/REVIEW_PACKET_*.md: 4 proof artifacts (full diff +
contract per file) used in DeepSeek per-file review.
Provenance chain (each step proof-anchored):
- MiniMax artifacts 2130e9e1d12d4686ac4d788bfd136673 (build pass 1) +
459bc9c00d6049dd949fa84e61f09c7a (build pass 2). BOTH truncated by
completion-token budget. Manual fixes preserved chain-of-custody:
(a) merge_conflict -> merge_git_fail (test class typo)
(b) test_state_route_returns_attempts re-authored from truncation
(c) `import secrets` added (MiniMax used secrets.token_hex without
adding the import)
(d) v1.5 future-proof fields added per user spec
- Per-file DeepSeek review APPROVE:
code_history.py proposal b63cd8b665bf4c2488591f8350b91cf5
review ev_5635d54ac7fdcec7
code_operator.py proposal 7b76f0eae91a4f0d8c80850fcef0b4f0
review ev_d9225ed939f77eb2
test_code_operator proposal 33d7dbc691b146f7a495c6c23fa148b0
review ev_4d1ca4217e6b226c
- Recovery cycle (gate failure -> targeted fix):
pytest NameError: redact_text -> follow-up proposal
fe2371073c3d4267b5e0e049df13e5b7 -> DeepSeek APPROVE
ev_5586c466df5d59aa -> applied evidence ev_647bfc4e38e0738f.
Gates after final apply:
- python -m py_compile (code_history.py + code_operator.py): exit 0
- python -m pytest test_code_operator.py: 50 passed
- scan_active_ui_no_fake.py: 81 files, 0 markers
- git diff --check: exit 0
- hermes_run_gate git-diff-check: PASS gate_git-diff-check_1778298845085
Provider smoke evidence still PASS: minimax ev_4a52d9b1336ca9f2,
deepseek ev_e708071cb269f170. No private values exposed.
Next slice (separate PRs): autonomous repair dispatch (v2), Hermes Agent
Task Monitor UI (v3). v0.13.0 upstream Hermes Agent update is its own
proof-gated lane.
Task: H3D-RECOVERY-CTL-V1
Hermes evidence: b63cd8b665bf4c2488591f8350b91cf5, 7b76f0eae91a4f0d8c80850fcef0b4f0, 33d7dbc691b146f7a495c6c23fa148b0, fe2371073c3d4267b5e0e049df13e5b7, ev_5635d54ac7fdcec7, ev_d9225ed939f77eb2, ev_4d1ca4217e6b226c, ev_5586c466df5d59aa, ev_788974be0aa90ccd, ev_cbdcc4bca447d895, ev_e1ba5ddf993149bb, ev_647bfc4e38e0738f, ev_4a52d9b1336ca9f2, ev_e708071cb269f170
* docs(gui): add Hermes3D OS visual reference pack (#134)
* fix(agent-updates): harden staged-update pytest gate (Audit PR #135 follow-up) (#136)
Mirrors upstream NousResearch/hermes-agent tests.yml flags so the staged
update gate cannot fake-pass while v0.13.0 is formally deferred. Closes
the CICD-SEC-1 / Codecov-2021-style fake-pass surface in
_run_update_checks.
Patch
- Path ignores: --ignore=tests/integration --ignore=tests/e2e match
upstream tests.yml. Marker-only -m "not integration" cannot block
tests/e2e/conftest.py from polluting sys.modules at collection time
(sys.modules["discord"] = MagicMock leak proven during Cplus-py311
Phase 4 bisection).
- Workers env: HERMES_AGENT_PYTEST_WORKERS (default "4", mirrors GHA
4-vCPU runner). Production rejects <2 with HTTPException(400);
HERMES_AGENT_DIAGNOSTIC=1 overrides for triage. "auto" sentinel
accepted. Garbage strings raise 400.
- maxfail: 1 in production (matches upstream tests.yml), 5 in
diagnostic mode for triage-friendly multi-failure output.
- Skip path now fail-closed: missing HERMES_AGENT_RUN_PYTEST surfaces
as status="fail" with "REQUIRES_CONFIRMATION:" output, never
status="skipped" or 200/OK. Removes the fake-pass path that let
pytest=skipped roll up as gate=verified.
- Timeout 300s -> 600s. Larger collected set under upstream-aligned
--ignore needs the longer budget.
Tests
- 04_testing/pytest/unit/test_agent_updates_meta.py (3 tests):
upstream tests.yml still has both --ignore= flags (network test,
skip-on-offline), local source mirrors them, diagnostic+workers
guard names + default value present.
- 04_testing/pytest/unit/test_agent_updates_skip_path.py (11 tests):
skip-path fail-closed when env unset/zero, workers 0/1 rejected in
production, workers 0 allowed in diagnostic mode, garbage raises
400, default workers="4", path-ignores in pytest args, diagnostic
uses --maxfail=5, "auto" sentinel accepted.
Result: 14/14 pass on 04_testing/pytest/unit.
Scope
- v0.13.0 update remains formally deferred (Cplus-defer-formal).
- This PR fixes the gate only; no runtime update was installed.
- Sources: PR #135 / commit 5ecd8ff (Batch 2 Agent 6 + Agent 10).
Follow-ups (separate PRs)
- Bonus 12: recovery ledger file lock, mark_recovery_outcome
idempotency, agent_updates.py:115 HTTPException auto-repair gap,
apply_patch_proposal TOCTOU.
- Bonus 13: 60-app audit doc errata (loader-real registry path,
42 SPDX-invalid licenses).
- Upstream Agent 11 tickets (firmware archive-dir validator deferred
here; YAML schema lacks the field today).
References
- https://raw.githubusercontent.com/NousResearch/hermes-agent/main/.github/workflows/tests.yml
- https://docs.pytest.org/en/stable/example/pythoncollection.html#ignore-paths-during-test-collection
- https://owasp.org/www-project-top-10-ci-cd-security-risks/
- https://about.codecov.io/apr-2021-post-mortem/
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(recovery): close Bonus 12 ledger races + auto-repair escape (PR #135) (#137)
Three findings from the Bonus 12 audit (PR #135 / bonus12-bug-finder.md):
Finding #1 (blocker, services/code_history.py recovery ledger)
- Append-without-lock allowed concurrent record_step_failure /
mark_recovery_outcome calls to interleave partial JSONL lines on
Windows. mark_recovery_outcome would silently json.JSONDecodeError-
skip the corrupted entries and report "attempt_id not found".
- Fix: new _RecoveryLedgerLock context manager that combines a
process-local threading.Lock with an OS-level advisory lock on a
sidecar lockfile. Uses fcntl.flock on POSIX and msvcrt.locking on
Windows; both stdlib, no new deps. flush()+os.fsync() on every
append.
Finding #2 (major, mark_recovery_outcome)
- No idempotency check: a retry could append a SECOND outcome row,
producing ambiguous state for list_recovery_attempts consumers.
- Fix: read scan now happens inside the same lock as the append.
If any outcome row for attempt_id already exists, raise
ValueError("already has a recorded outcome") atomically.
Finding #3 (major, agent_updates.py:115)
- _run_git raises HTTPException(502) on non-zero exit. A failed
mid-step "git checkout --detach <tag>" escaped the for-tag loop
without reaching _auto_repair_to_backup, leaving the Hermes Agent
checkout on the previous (still-unverified) tag and surfacing 502
to the caller instead of structured rollback.
- Fix: wrap the per-tag checkout + _run_update_checks in
try/except HTTPException; record a synthetic step failure with the
redacted detail and pivot to _auto_repair_to_backup. Also catches
the HERMES_AGENT_PYTEST_WORKERS validation 400 added in PR #136.
Tests added (11 total, all green)
- 04_testing/pytest/unit/test_recovery_ledger_locking.py (8 tests)
* lock helper exposes a backend (fcntl/msvcrt/thread-only)
* 12-thread x 25-write concurrency test: every line round-trips
through json.loads (no torn writes)
* record_step_failure writes complete JSONL line + creates parent
directory + lockfile sidecar
* mark_recovery_outcome first call succeeds; second call raises
ValueError with "already has a recorded outcome"
* unknown attempt_id still raises "not found in recovery ledger"
* race test: two threads finalize same attempt_id; exactly one
succeeds, one raises idempotency error
- 04_testing/pytest/unit/test_agent_updates_auto_repair.py (3 tests)
* failed checkout pivots to _auto_repair_to_backup (no 502 escape)
* failed _run_update_checks (workers env 400) also pivots
* all-pass path unchanged (smoke regression guard)
Verification
- py_compile: OK on all 4 files
- Focused tests: 25/25 pass (11 new + 14 from PR #136)
- Pre-existing failures in test_source_runtime_contracts.py (5
firmware tests blocked instead of ready) confirmed pre-existing
on base; out of scope for this PR.
Scope
- Recovery Controller v2 (RC v2) commits 2-5 stay paused per user
instruction; RC v2 depends on the recovery correctness this PR
restores.
- Hermes Agent v0.13.0 update remains formally deferred.
- Bonus 13 audit doc errata is out of scope (separate PR).
References
- https://docs.python.org/3/library/fcntl.html#fcntl.flock
- https://docs.python.org/3/library/msvcrt.html#msvcrt.locking
- https://about.codecov.io/apr-2021-post-mortem/
- https://owasp.org/www-project-top-10-ci-cd-security-risks/
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(agent-updates): harden _zip_dirty_entries (Bonus 12 #4 / PR #135) (#138)
Defense-in-depth on the dirty-files backup zip in
api/routes/agent_updates.py:_zip_dirty_entries.
Pre-fix issues
- Opened the zip without allowZip64=True, so >4 GiB dirty backups
silently truncate on Python builds that default to no-zip64.
- Used path.relative_to(repo) against an un-resolved repo path,
raising ValueError and aborting the whole backup whenever the repo
path is itself a symlink.
- A symlink in the dirty tree could resolve to a target outside the
repo and still produce an arcname inside the archive, surfacing
CWE-22 path traversal on extract.
Post-fix
- allowZip64=True passed to ZipFile.
- path.is_symlink() check skips symlinks defensively (even though
_dirty_entries usually pre-resolves; tests / future callers may not).
- Arcname computed against repo.resolve() so symlinked checkouts
(e.g. /tmp/repo -> /var/checkout) work cleanly.
- Arcname asserted to be a pure relative path (no absolute,
drive-letter, parent-traversal, or empty components).
- Resolved-target paths that fall outside the repo are silently
dropped instead of leaking into the archive.
Tests added (8, all green)
- 04_testing/pytest/unit/test_agent_updates_zip_dirty.py
* normal files round-trip with relative arcnames
* empty paths list short-circuits without creating an archive
* symlinks (in-repo target) skipped — CWE-22 guard
* symlinks (out-of-repo target) skipped — exfiltration guard
* symlinked repo root produces correct arcname (no ValueError)
* out-of-repo path silently dropped
* allowZip64=True passed (probe via ZipFile subclass)
* pathological absolute Path components silently dropped
Verification
- py_compile: OK
- 25/25 agent_updates-keyed unit tests pass
- Secret-leak scan on touched files: only descriptive test fixture
string "outside-secret" (not a real secret)
- Pre-push hook: passed
Scope
- Bonus 12 finding #4 only (continuing the controlled-batch pattern
from PR #137).
- v0.13.0 update remains formally deferred.
- RC v2 commits 2-5 remain paused per user instruction.
References
- https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile
- https://cwe.mitre.org/data/definitions/22.html
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(audit): 60-App Update Readiness Audit (docs-only, no runtime change) (#135)
* docs(audit): 60-App Update Readiness Audit + Phase 4 v2 patch proposal
Audit/planning lane only. No app updates. No GUI changes. No source mutation
beyond this doc. Hermes Agent v0.13.0 stays formally deferred per the
2026-05-09 user decision in handoffs/HERMES_AGENT_V013_UPDATE_LANE_CPLUS_PY311_DOCKER_FORMAL_DEFER.
What's in the audit:
- Per-app profile matrix: 60 rows across 11 sections (slicers 11 / modelers 13
/ 3D-gen 6 / print-farm 10 / firmware 6 / agent-cli 7 / library 1 / materials
1 / hardware 3 / utilities 1 / research 1). Each row: update method, proof
command, runtime env, deps, rollback method, blockers, recommended lane,
auto-upd…
Hermes evidence chain: PASS
Task ID: H3D-CLAUDE-POLISH-RELEASE-DOCS-2026-05-06
Agent: claude-polish-docs-06 (Audit Agent 6 of 6)
hermes_run_gate: PASS (pre-push: Layer A forbidden-pattern PASS, Layer B 39 unit tests PASS)
Summary
Polish/correctness audit of all 20 lane PR bodies (#53–#72), ROADMAP.md accuracy, README overclaim check, TS7026 blocker documentation, and merge plan verification.
Files changed
03_implementation/docs/handoffs/audit/RELEASE_DOCS_2026-05-06.mdGates run
hermes_doctor: ok=truehermes_lock_files: audit report file locked (ID: 9120838e2de2dc8a084815ee)gh pr viewDocumentation gaps found
Blockers
None — all findings are documentation gaps only. No code regressions introduced.
Test plan
🤖 Generated with Claude Code