Skip to content

governance: contribution harness, decisions register and Watchdog - #38

Merged
BotshareAI merged 130 commits into
mainfrom
claude/brave-hypatia-lv9zbv
Oct 8, 2026
Merged

BotshareAI merged 130 commits into
mainfrom
claude/brave-hypatia-lv9zbv

Conversation

@BotshareAI

@BotshareAI BotshareAI commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds the OpenAMRobot contribution and agent harness to openAMRobot/.github:

  • general process rules (AGENTS.md, CONTRIBUTING.md);
  • a separate register of approved technical decisions (decisions.yaml);
  • checkers with tests, and templates;
  • rollout material for the other repositories.

It follows the principle agent = model + harness. Every rule is labelled in one of three ways:

  • a check, only where a checker detects the violation;
  • a template;
  • a human gate, with a named reviewer and the evidence they need.

The checks block a merge in another repository only after that repository opts in (harness_warn, then harness_checks) and its ruleset requires them, which is the rollout described in rollout/README.md. What merging this PR changes elsewhere without any opt-in is listed under "Repositories affected on merge".

Merging activates the Watchdog organization scan. .github/workflows/watchdog-org-scan.yml is an installed workflow in this repository, not a rollout example. After merge it runs every Thursday at 14:00 Berlin time (Europe/Berlin) and on manual dispatch, clones the 14 repositories in rollout/repositories.yaml read-only, and writes the "[watchdog] Organization dashboard" issue in openAMRobot/.github. It never pushes, never opens pull requests and runs no AI agent.

The OpenAMRobot Watchdog

The Watchdog is the deterministic check layer of this harness: it compares every repository with the approved decisions in decisions.yaml and with the public-extract, shared-rules and workflow-pinning rules, and tells the contributor what was found, why it matters and exactly how to fix it. It uses no AI, reads files only, and proves textual consistency only, never safety, electrical, mechanical or release correctness.

  • Tools. tools/watchdog_scan_support.py holds the fail-closed steps of the organization scan (repository list, BLOCKED records, report enrichment, completeness check); tools/watchdog.py runs every repository check against one checkout (python3 tools/watchdog.py --root ../openamrobot-docs); tools/watchdog_report.py is the shared output (guidance once per decision, then each finding as file:line; inline annotations and a Markdown job summary in GitHub Actions; full detail per finding in JSON); tools/watchdog_issue_sync.py publishes the organization result as GitHub issues.
  • Guide. WATCHDOG.md, linked from README.md and CONTRIBUTING.md: the checks, how to read and fix a finding, the words each decision accepts, approved public contacts, local and CI use, the issue mode, adoption and FAQ.
  • Issue template. .github/ISSUE_TEMPLATE/decision_review.yml ("Decision register review") for confirming or changing one decisions.yaml entry after a review reminder; the register is still changed only through a reviewed pull request.
  • Installed workflow .github/workflows/watchdog-org-scan.yml:
    • every Thursday at 14:00 Berlin time (cron: "0 14 * * 4" with timezone: "Europe/Berlin", so it follows daylight saving time) plus manual dispatch;
    • read-only, anonymous --depth 1 clones of the default branch of each repository in rollout/repositories.yaml (14 repositories);
    • permissions contents: read and issues: write only;
    • no pushes, no pull requests, no AI agent, no change to decisions.yaml;
    • dashboard-only issue mode by default: with the repository variable WATCHDOG_ISSUE_MODE unset, it creates or updates in place only the single "[watchdog] Organization dashboard" issue, which lists every active group (repository, check, group, finding count, owner, file links) and every scan-blocked repository. WATCHDOG_ISSUE_MODE=groups adds one deduplicated issue per group; the platform lead decides when to switch;
    • fail closed: a repository that cannot be listed, cloned, scanned or reported is BLOCKED; the run is then INCOMPLETE (summary heading and dashboard banner), missing repositories are never treated as clean, and the job fails. See "CI/CD review of 8 Oct: fail-closed scan" below.

A dashboard row group reads like the terminal output:

Mismatch with approved decision: COMPUTE (14 finding(s))
  Decision: Reference compute: NVIDIA Jetson Orin NX 16 GB on a reComputer Robotics J401; Pi is legacy.
  Why:      Jetson Orin NX is the 2.0 reference compute; label Raspberry Pi material as legacy.
  Fix:      Name the Jetson Orin NX, or label Raspberry Pi material as legacy or Gate A.
  More:     COMPUTE in decisions.yaml: .../decisions.yaml#L711 | WATCHDOG.md: .../WATCHDOG.md#decisions-of-record
  Found:
    README.md:44: found 'Raspberry Pi 5'
    README.md:81: found 'Raspberry Pi 5'
    ...

Work package

No work-package issue exists. The task came directly from the platform lead and is scoped to openAMRobot/.github; changes needed in other repositories are delivered as files under rollout/.

What this closes

The table lists the recurring failure classes in the 28 September alignment audit, grouped by ID prefix. None of the audit's content was copied into this repository. For each class the table gives the rule and the state of the mechanism that addresses it:

  • (a) implemented and tested here;
  • (b) a rollout example, not installed anywhere;
  • (c) a human gate.

A text check proves textual consistency with the register only, never mechanical, electrical or safety correctness.

Prefix Recurring class Mechanism and state
GEO Superseded mast baseline and positions; lift status; 1700 mm read as a shoulder height; speed ceiling read as operating speed; height datum and frames LIFT (approved in principle, P-03 rev18.7 item 8), the three mast entries marked superseded with citation patterns, MAX-ASSEMBLED-HEIGHT, SPEED-CEILING, DATUM-HEIGHT-STACK and FRAMES-REP105 (a). Substance: platform lead with drawings (c)
BOM Canonical BOM issue unresolved; procurement boundary and charge-route wording; battery placement BOM-ISSUE-IN-FORCE recorded as Issue 7.3 (P-03 rev18.7), with checks for Issue 6, other 7.x issues or B-01 presented as canonical (a); SAFETY-PROCUREMENT, DOCK-NO-CONTACTS and BATTERY-PLACEMENT wording checks (a)
ELE IMU topic attributed to firmware; legacy compute, camera and LiDAR presented as current; docking read as charging; gate roles inverted; RS485 and 12 V remnants; controller I/O IMU-TOPIC-OWNERSHIP, COMPUTE, CAMERAS, HEAD-CAMERA-IDENTITY, NAV-LIDAR, DOCKING-NOT-CHARGING, BASE-CONTROLLER-GATES, BASE-CONTROLLER-IO, RS485-NOT-IN-2-0 and POWER-RAILS (a). Topic ownership on a running system: software lead (c)
SW Contracts diverging between repositories; unpinned callers; licence tags that do not match "Changing a decision" process and contract change request form (template); harness_ref pinning (b); licence map (c)
CI Zero-test suites passing; no build gate; no shared verification harness verify.sh zero-test and skip-issue rules (a); the quality/test job in callers (b)
PR xfail or importorskip that hides a non-running test; PR text that overstates what ran Skip rule in verify.sh (a); check_pr_evidence.py for sections, SHAs, commands and counts (a) as installed by pr-assistant.yml (b); whether commands were really run: reviewer (c)
TEAM Review routing to one account; AGENTS.md claimed but absent; no handle mapping maintainers.yaml (a); CODEOWNERS proposal in rollout/README.md (b); drift check (a)
DOC Internal links, prices and names in public assets; private links in AGENTS.md; uncertified E-stop advice; decisions shown as recorded early; legacy build shown as current; unverified technical claims check_public_extract.py (a) under the canonical documentation policy in openamrobot-docs; SAFETY-PROCUREMENT wording check (a) plus platform lead (c); register provenance (a) with owner confirmation (c); docs-fix prompt separates verified from planned content (template)

What changed

75 files change against main (61 added, 13 modified, 1 renamed). .github/CODEOWNERS is not among them.

  • CONTRIBUTING.md: the contributor path on one page. It points to "Changing a decision" and says checks block merges only once installed and required. Its example exclusion is "no RS485 in 2.0".
  • AGENTS.md / agent-rules/SHARED_RULES.md (shared block v2):
    • Process only.
    • "Changing a decision": change request issue, then the source document, then one reviewed PR for the register and its consumers, then owner approval. No tool rewrites the register or a source.
    • Labels: [check] only where a checker detects the violation; otherwise [template] or [human: role, evidence].
    • No internal links or personal names.
  • decisions.yaml: 27 entries by status: 23 recorded, 1 open (DRIVE-TRACK) and 3 superseded (MAST-INSTALL-HEIGHT, MAST-POSITIONS, MAST-TOP-HEIGHT). Every entry has the optional one-line summary and fix_hint used in findings.
    • Every entry has kind, scope (repositories and file globs), owner, provenance, supersession and a verification method: what the scan detects, and which reviewer checks what evidence.

    • Sources: P-03 rev18.7 (6 October 2026) is the addendum in force; revisions 18.6, 18.5, 18.4, 18.3 and 18.2 are earlier revisions. BOM Issue 7.3 is canonical; Issue 7 is the earlier issue. All are provenance only; CI reads only the pinned register.

    • LIFT (P-03 rev18.7 item 8) replaces LIFT-REMOVED.

      • The lift is approved in principle: DOLD Hexalift V1 350 mm primary, TiMOTION TL3 400 mm fallback.
      • Shoulder axis 1000 to 1350 mm; base plate fore-aft positions centre, +50, +100, +150 and +200 mm.
      • Lift motion only in the stowed or carry safe pose with the base stopped; hold-and-move limits 0.05 m/s (drawer reversal) and 0.3 m/s (carrying).
      • Holding on E-stop and power loss, supplier CAD, base-plate geometry and the CAN3 lift interface remain release gates (items 6, 8, 14, 15).
      • Its check flags text that says 2.0 has no lift, presents a fixed mast as the current baseline, or defers the lift to 3.0.
    • Superseded entries: MAST-INSTALL-HEIGHT, MAST-POSITIONS and MAST-TOP-HEIGHT are superseded by item 8. Only their citation patterns are scanned, for text still presenting the fixed-mast value as current. MAX-ASSEMBLED-HEIGHT stays 1700 mm (item 8).

    • DATUM-HEIGHT-STACK (item 15):

      • floor Z = 0; steel chassis deck top 294 mm (MMP STEP);
      • top cover 2 mm plastic, or optional 0.5 to 0.8 mm sheet metal;
      • a 10 mm aluminium lift base plate bears on the steel deck, with the cover cut out around it;
      • the base-plate top face at 304 mm is the reference for lift and shoulder heights.
    • FRAMES-REP105 (item 15): base_footprint on the floor under the drive-axle midpoint; base_link at the axle midpoint and axle height, x forward, z up; imu_link on the centreline away from motor magnetic fields.

    • BATTERY-PLACEMENT (item 9): as close to the rear edge as practical while preserving enclosure, service and safety clearances; the 25 percent position is superseded.

    • BASE-CONTROLLER-IO (item 14):

      • STM32H723ZG on the NUCLEO-H723ZG;
      • two MaxBotix MB7060 serial sensors, each on one dedicated STM32 UART at 9600 8N1, and no sensor I2C off the controller board (MB7040 on I2C is superseded);
      • CAN1 traction only, CAN2 BMS, CAN3 reserved for upper-body auxiliary actuators (CANopen, no safety function);
      • MCU to Jetson over Ethernet with micro-ROS over UDP; USB for the bench only.
    • HEAD-CAMERA-IDENTITY is recorded (item 15): Stereolabs ZED Mini, SKU ZED-121210, supplied with the OpenArm 2.0 set, on the lift carriage, pitch 15 to 35 degrees down in 5 degree steps, baseline 25.

    • CAMERAS: the base Gemini 336L sits about 243 mm above the floor, with up-tilt positions 5, 10 and 15 degrees, baseline 10 (item 15).

    • NAV-LIDAR: the SLAMTEC RPLIDAR S3 (S3M1-R2) on USB and the regulated 5 V rail (P-03 rev18.4 item 13).

    • RELEASE-MILESTONES (P-03 rev18.6 item 12):

      • v2.0.0-rc.1 GitHub pre-release on 20 November 2026, ending development cycle 2;
      • physical integration, testing and acceptance from 23 November to 18 December 2026;
      • v2.0.0 final release on 18 December 2026.

      Its checks also flag a v0.2 release and a development cycle ending 13 November 2026 without a superseded label.

    • Unchanged in this round: the distinctions and exclusions (the 1700 mm envelope, no suspension, no RS485, no dock contacts or pilot, docking never establishes charging, telemetry never safety evidence).

  • tools/check_decisions.py:
    • Validates the register, including the new superseded status (superseded_by with document, item, optional decision and citation).
    • Scans the listed file types and reports file, line and found value, with the decision in one line, why it matters, how to fix it and links (Round 8 format).
    • Reports text still citing a superseded source or presenting a superseded entry as current.
    • Counts files it did not scan and states the textual-only limit.
    • Never writes.
  • tools/check_public_extract.py: reports Drive and Docs links, e-mail addresses, phone numbers, prices and credentials. The canonical documentation policy is openamrobot-docs/docs/DOCUMENTATION_STANDARD.md. The allowlist is an implementation detail that separates intentional public content (contact, licensing, documentation) from accidental leakage.
  • tools/check_pr_evidence.py:
    • Checks sections, SHAs, commands, test counts, dependencies and STATE.md.
    • For safety paths it reports "safety path touched, two human approvals required" and checks that reviewers are requested; approvals are a ruleset requirement.
    • Deleted and renamed files are covered (changed_all.txt).
    • Checker errors fail closed.
  • rollout/verify.sh and VERIFY.md:
    • Follows and delegates to the interfaces verify.sh. Adds the zero-tests and skip-issue rules and writes summary.json, also for delegated runs.
    • Stages run under env -i with a fresh HOME. The caller's rosdep sources list and cache are copied in, and ROSDEP_SOURCE_PATH is passed through.
    • rosdep check scans only the ROS source packages, never build/, install/, log/ or COLCON_IGNORE folders.
    • VERIFY_ROS_SETUP can replace the ROS setup file.
  • .gitattributes: LF line endings for *.sh and *.bash.
  • Templates:
    • PR template.
    • Issue forms: bug, contract change request, harness mistake, good first issue, decision register review.
    • rollout/STATE.md.example.
    • Four agent prompts, each with a precondition block, an expected outcome and the failure rule. docs-fix.md (template version 2) separates verified facts, which carry a source reference in the owning repository, from labelled planned or experimental content, and forbids inventing a technical claim.
  • rollout/workflows/: pr-assistant, weekly-alignment-audit, docs-sync plus caller, and monthly-retro. Each file is marked as an example or a design.
    • SETUP.md classifies every check and workflow as (a), (b) or (c) and names the canonical documentation policy.
    • tools/sync_audit_issues.py never closes an issue.
  • rollout/README.md: adoption order (a) to (e) with the openamrobot-interfaces pilot and its eight exit criteria, release-manifest interaction, and a CODEOWNERS proposal for the other repositories (not applied) naming @wikki26, @anandgawai123456-glitch and @KARTHIKEYAN124.
  • maintainers.yaml: platform-lead BotshareAI, software-lead panthera-momagdii, ci-owner wikki26, release-owner KARTHIKEYAN124, docs-owner anandgawai123456-glitch.
  • Public text in this repository:
    • profile/README.md: the lift is approved in principle for OpenAMRobot 2.0 (release gates still open), in the overview, repository tree, repository table and roadmap. The footer address is "Chrysanthou Mylona 1, Panayides Building, Floor 2, Office 1, 3030 Limassol, Cyprus".
    • ENGINEERING_QUALITY_STANDARD.md: development cycle 2 ends 20 November 2026 with v2.0.0-rc.1, and v2.0.0 follows on 18 December 2026. The v0.2 readiness declaration is removed.
    • ROADMAP.md: the Jetson Orin NX is the 2.0 compute.
  • Watchdog: tools/watchdog.py, tools/watchdog_report.py, tools/watchdog_issue_sync.py, WATCHDOG.md, public-extract-allowlist.yaml (approved public contacts), rollout/repositories.yaml and the installed .github/workflows/watchdog-org-scan.yml, described above.
  • Reusable workflow: repository-quality-reusable.yml gains the decisions, public-extract and drift steps behind harness_checks: true (blocking) or harness_warn: true (warnings only), both off by default.
    • Its checkout uses fetch-depth: 0 only when one of them is true; default callers keep the shallow checkout.
    • There is also an opt-in quality/test job.
    • This repository's own caller opts in.

Repositories affected on merge

Without any opt-in, merging changes these organization-wide defaults. The repositories were checked on fresh main checkouts on 7 October.

  • The Watchdog organization scan starts running. .github/workflows/watchdog-org-scan.yml runs from this repository's default branch every Thursday at 14:00 Europe/Berlin and on manual dispatch. It clones the 14 repositories in rollout/repositories.yaml read-only and does not change them. In this repository it creates the watchdog-report label if missing and creates, then edits in place, the "[watchdog] Organization dashboard" issue. With WATCHDOG_ISSUE_MODE unset no other issue is written. It needs no secret beyond the workflow's GITHUB_TOKEN.
  • Reusable workflow, all 13 callers: openamr-platform-sw, openamr-platform-fw, openamr-platform-hw, openamr-upperbody-sw, openamr-upperbody-fw, openamr-upperbody-hw, openamrobot-interfaces, openamrobot-manipulation, openamrobot-ui, openamrobot-comm, openamrobot-docs, openamrobot-manifest and openamrobot-release.
    • All 13 call repository-quality-reusable.yml@main, and none sets the new inputs.
    • Their repository-quality job runs the new file. The harness steps stay off, the quality/test job stays off, and the checkout stays shallow. The governance-baseline steps are unchanged.
  • Default issue forms: 12 of the 13 have no .github/ISSUE_TEMPLATE of their own; only openamr-platform-sw has one. Those 12 get the changed defaults:
    • the bug form;
    • the contract change request form (renamed from interface change request);
    • the new harness-mistake, good-first-issue and decision-register-review forms.
  • Default PR template and CONTRIBUTING.md: each of the 13 has its own, so neither default changes anything in them. The defaults apply to any repository without its own, which includes repositories outside this session's access.

Integration Gate

Reused and extended:

  • check_agent_rules.py, extended to read the marker version.
  • repository-quality-reusable.yml, with its steps kept.
  • The interface change request form, renamed to contract change request.
  • The interfaces tools/verify.sh design, delegated to rather than copied.
  • The empty-suite rule from interfaces run_verification_tests.py.
  • The docs repository's check_docs.sh, called through VERIFY_TEST.

Rejected:

  • Fetching Drive or the docs site in CI: the register is the only CI input.
  • Blocking full scans on push: existing debt would turn repositories red without blocking anything.
  • Enabling the harness steps for existing @main callers on merge: that would change other repositories without their owners.
  • Auto-closing audit issues.
  • An LLM step in the PR assistant.
  • Running the Claude Code action on push: the action does not support that event.
  • One issue per finding group by default: about 70 issues on the first run would bury the owners; the default is one dashboard, and per-group issues are a platform-lead switch.

Changes after review

Round 1, commit e86f68c: merge with main (already up to date); .github/CODEOWNERS restored to main's version; NAV-LIDAR is the RPLIDAR S3 (P-03 rev18.4 item 13) with Hokuyo and A1 superseded; POWER-RAILS on the regulated 5 V rail; RELEASE-MILESTONES added; COMPUTE source item fixed; maintainers ci-owner wikki26 and docs-owner anandgawai123456-glitch; register tests that fail against the previous register.

Round 2, commit 0fa9b64: P-03-rev18.4 in force; the maintainers.yaml header describes main's CODEOWNERS; rollout/README.md handles filled in; description rewritten.

Round 3, commit 066f580: Gate B is the STM32H723ZG on the NUCLEO-H723ZG; P-03-rev18.5 added; new entry BASE-CONTROLLER-IO.

Round 4, commit cc02725: P-03-rev18.5 in force; register test for BASE-CONTROLLER-IO.

Round 5, commit fcf3d8ae7e73: P-03-rev18.6 in force; RELEASE-MILESTONES versions v2.0.0-rc.1 and v2.0.0 (P-03-rev18.6 item 12).

Round 6, commits 4a88e50 to 458ea3b (20 commits, each signed off). Every register commit carries a register test that fails against the previous register; the failure is quoted in its commit message.

  • P-03 rev18.7 register realignment:
    • 4a88e50: rev18.7 is in force, and LIFT replaces LIFT-REMOVED.
    • 59c0162: the mast entries are superseded and the checker gains the superseded status.
    • f22ac15: DATUM-HEIGHT-STACK.
    • 9440797: FRAMES-REP105.
    • 0a119aa: BOM Issue 7.3.
    • 4f6d844: BATTERY-PLACEMENT.
    • cd6d72d: BASE-CONTROLLER-IO.
    • fc30389: HEAD-CAMERA-IDENTITY recorded, plus the CAMERAS tilt.
    • 2f97618: RELEASE-MILESTONES flags v0.2 and a 13 November cycle end.
    • 458ea3b: the LIFT check is tightened after the cross-repository dry run.
  • Public text: fd399a7 (profile lift wording and footer address), 9d7d4a3 (CONTRIBUTING example), 7c7f108 (ENGINEERING_QUALITY_STANDARD cycle and release wording).
  • CI owner review (6 October):
  • Documentation owner review (4 October):
    • 09038a6: DOCUMENTATION_STANDARD.md is canonical and the allowlist is an implementation detail.
    • dbaa647: docs-fix separates verified from planned content.

Round 7, commits after 458ea3b (head 774f2ad). This review pass closes the concrete pre-merge findings and keeps activation gated:

  • live workflow actions are pinned to full commit SHAs, with a checker that rejects tags, branches, missing refs and <HARNESS_SHA> in live workflows;
  • enforcing callers fail when AGENTS.md is missing unless they provide a non-empty, summarized exception reason;
  • AI disclosure checks cover PR text and commit messages and require the named tool plus scope of assistance;
  • decision metadata now has an in-force source/date and per-entry review_by dates, with non-blocking audit warnings after expiry;
  • platform-lead-authored PRs require the software lead and every scoped owner; the author's reconciliation is explicitly not an approval;
  • the PR template records the Use_Case_1/no-private-name condition;
  • the ROS smoke test is real and green; its initial self-copy, Python-schema, and missing-Cyclone-DDS failures were fixed and regression-tested;
  • API-key examples retain id-token: write for the official Claude GitHub App path; Anthropic OIDC federation is a separately documented alternative and remains gated by issue Activation gate for AI workflows (docs-sync, weekly audit, monthly retro) #43.
  • activation follow-ups are tracked in #43, and the micro_ros_agent verifier blocker in openamr-platform-sw#50.

Round 8, the Watchdog (commits 3110898 to e75c3b5, six commits, each signed off). No decision value changed.

  • 3110898, friendly output. check_decisions.py, check_public_extract.py, check_agent_rules.py and check_workflow_policy.py print each finding as label: file:line: ID found 'text' plus Decision (or Rule), Why, Fix and More (links to WATCHDOG.md and the register entry's line), grouped by decision with counts, then a closing summary and the next step. Labels: "Mismatch with approved decision", "Should not be public", "Shared agent rules out of date", "Workflow not pinned", "Placeholder left in workflow". What they detect, their exit codes and the result: lines are unchanged. New shared module tools/watchdog_report.py. Inside GitHub Actions each finding is also a workflow annotation (warning, or error when enforcing on a pull request) and a Markdown job summary with the grouped table and collapsible details; the reusable workflow sets WATCHDOG_ANNOTATION instead of the old grep/sed annotation lines. check_pr_evidence.py parses the new header. Two optional register fields, summary and fix_hint (one line, at most 120 characters, schema-validated), are filled for all 27 entries from the existing value and message text; the long value stays in the register and is no longer printed per finding.

  • bcbc07a, false-positive review. Every one of the 193 decision findings in the scan below was read on its source line. Only two lines clearly label historical material, and only their unless patterns changed, each with a regression test (fails before, passes after; a current-tense line still fails):

    • IMU-TOPIC-OWNERSHIP accepts outdated and older revision(s): openamr-platform-hw electrical/sensors/imu.md:31, "Older revisions of this doc said the firmware publishes /imu/data directly — that is outdated".
    • DOCKING-NOT-CHARGING accepts legacy: openamr-platform-sw ros2/src/openamrobot_docking/config/dock_trigger.yaml:25, "# Legacy fields read by opennav_docking::SimpleChargingDock".

    Not adjusted, because the line does not label history or 3.0 (reported for the decision owners): MPU6050 lines that explain the board is really an MPU6500 (BASE-CONTROLLER-GATES, 7 lines); the upstream Nav2 class name SimpleChargingDock (DOCKING-NOT-CHARGING, 10 lines); "RealSense ... an anticipated direction ... not a committed change" (CAMERAS); "wireless charging ... not on the base build" (DOCK-NO-CONTACTS). Every LIFT, MAST-* and "fixed mast" finding is a real mismatch under rev18.7 item 8 (lift approved in principle for 2.0).

  • cf77d4c, tools/watchdog.py. Runs decisions of record, public extract, shared agent rules (when AGENTS.md exists), workflow policy and decision freshness against one checkout with this harness's register, then prints one summary grouped by decision. --report-only, --json, --markdown, --accepted-words. Exit 0 clean, 1 findings, 2 configuration error.

  • 87e9561, .github/workflows/watchdog-org-scan.yml. Deterministic, no AI, permissions: contents: read, weekly (Monday 06:17 UTC) and manual dispatch, actions pinned to full SHAs. Clones the 14 repositories in the new rollout/repositories.yaml on their default branch, runs tools/watchdog.py --report-only, and writes one job summary with a table per repository and a link to WATCHDOG.md. Findings never fail the job; it never pushes, opens issues or comments. A clone failure is shown as BLOCKED and fails the job after the summary, so an incomplete scan is not shown as complete.

  • b406a5a, WATCHDOG.md, linked from README.md and CONTRIBUTING.md: what it is and is not, the checks table (what, why, typical finding, fix, owner), a real finding before and after the fix, how to fix (correct the line, label history with the words each decision accepts, or open a contract change request; never weaken a check), local and CI use, the adoption checklist (interfaces pilot first), AI-workflow status (design only until Activation gate for AI workflows (docs-sync, weekly audit, monthly retro) #43 closes) and an FAQ. The accepted-words table is generated by tools/watchdog.py --accepted-words and a test keeps it identical to the register. The register's global exclude gains the root WATCHDOG.md only, because the guide quotes findings and register messages; a test shows docs/WATCHDOG.md elsewhere is still scanned.

  • e75c3b5, test isolation. The first CI run of this round (run 37661236604, green) showed three spurious ##[error] annotations from the formatter tests in its quality/test log, and checker tests could append to the real job summary. Test modules that exercise the output now drop the GitHub Actions variables, and a new test runs the whole suite as a child with GITHUB_ACTIONS=true and fails on any annotation line or summary write.

Round 9, approved public contacts and compact output (commits 48519d5 to 4ea9bd4, three commits, each signed off; head 4ea9bd4). No decision value changed.

  • 48519d5, compact output. tools/watchdog_report.py prints one block per decision (or rule): label, ID and count, then Decision, Why (one line per distinct reason), Fix and More once, then every finding as file:line: found '...'. Annotations and the JSON output keep full detail per finding. check_pr_evidence.py reads the grouped report and produces the same failure lines as before; a new test feeds it the real check_decisions.py output. Detection, exit codes and result: lines are unchanged.

  • 172f9c6, approved public contacts in public-extract-allowlist.yaml, each entry with its reason; existing entries kept, no price entry added:

    • organisation: any address on the botshare.ai domain (or a subdomain);
    • contributors and maintainers: any address on a Signed-off-by: or Co-authored-by: line, and any address in CONTRIBUTORS.md, MAINTAINERS.md or maintainers.yaml (publication agreed through the DCO, CLA and contributor privacy notice);
    • supplier role addresses: in datasheets/** only, local part sales, info, support, service, contact, export, trade, office or marketing, optionally followed by digits.

    Regression tests: each allowed case passes; a personal supplier address in datasheets/, the lookalike domains botshare-ai.com, botshare.ai.example.org and notbotshare.ai, a role address outside datasheets/ and prices in datasheets/ are still flagged. The existing assertion that someone@botshare.ai is flagged was changed to allowed, as item (a) requires.

  • 4ea9bd4, WATCHDOG.md: new section "Approved public contacts" (the four kinds: organisation, contributors and maintainers, supplier role addresses in datasheets/ only, third-party licence notices; prices never public except the approved organisation pricing; the docs owner decides entries for published pages, the platform lead for company or commercial information). "How to read a finding" and the checks table show the grouped format with the real COMPUTE group from the openamr-platform-hw scan.

  • Related, separate repository: openAMRobot/openamr-platform-hw#17 (open) removes the ZLTech supplier price list and personal supplier contact data from datasheets/; with this round's allowlist its datasheets/ folder has no public-extract findings.

Round 10, Watchdog issue publication, dashboard-only default and Berlin schedule (head 8ecda44). No decision value changed.

  • GitHub issue publication (commits e87f75a to 12a64bc, unchanged, and the six rewritten commits listed under DCO rewrite): tools/watchdog_issue_sync.py turns the organization scan into GitHub issues in openAMRobot/.github: stable deduplication per repository, check and group; redaction of URLs, e-mail addresses and credential-shaped text; comments only when the evidence changes; "no longer detected" comments instead of closing; reopening when a closed finding returns; review reminders for due review_by dates; BLOCKED handling; the label vocabulary created on demand; the decision_review.yml issue form; the dashboard's shared-rules enrolment column (pass, drift, not enrolled). The workflow moved to Thursday with issues: write; this supersedes the Round 8 description of a Monday, issue-free scan.
  • 43f2804, issue mode switch. The repository variable WATCHDOG_ISSUE_MODE, read by the workflow (vars.WATCHDOG_ISSUE_MODE) and by tools/watchdog_issue_sync.py: unset or dashboard (default) creates or edits in place only "[watchdog] Organization dashboard", listing every active group with repository, check, group, finding count, owner and file links (at most five links per group, then "and N more"); groups keeps the per-group issues; any other value stops the sync with exit 2. Scan-blocked repositories always appear on the dashboard. Documented in WATCHDOG.md ("Watchdog issue mode": how to turn on per-group issues, and that the platform lead decides when) and in the workflow comments.
  • Schedule: Thursday 14:00 Berlin time (confirmed by the platform lead). f7c6d96 sets cron: "0 14 * * 4" with timezone: "Europe/Berlin" (was 17 6 * * 4, 06:17 UTC); 5a8b313 updates the workflow test to the new cron and timezone; 18d8a2b updates WATCHDOG.md, rollout/workflows/SETUP.md (which also says that only the dashboard issue is written while WATCHDOG_ISSUE_MODE is unset) and the workflow header comment.
  • DCO rewrite. Commits b2b209f and 9aaae03 had no Signed-off-by line. As instructed, git rebase --signoff 12a64bc (the parent of 9aaae03) rewrote only the six commits after it, with no merge commit in that range, keeping authors, content and order, and the branch was pushed with --force-with-lease: 9aaae03 → 2dd01e1, 3e6ac3c → cdbdb22, 50a4747 → 0449955, b2b209f → f3c2fb8, 3bd038f → 07e3f50, 2829903 → 5039b53. The two schedule commits arrived on the branch without sign-off (0329752, b562360) and were signed off the same way (git rebase --signoff 43f2804, no merge commit in range, authors and content kept, --force-with-lease against b562360): 0329752 → f7c6d96, b562360 → 5a8b313; the tree of 5a8b313 equals b562360. Checked afterwards: all 126 non-merge commits in origin/main..HEAD carry Signed-off-by: Alex Reznichenko <info@botshare.ai>; the tree of 5039b53 equals the tree of 2829903, and 43f2804 differed from 2829903 only by the issue-mode commit (6 files).
  • 8ecda44, summary wording. The organization scan's job summary no longer says findings are synchronized to deduplicated issues; it says results are published to the "[watchdog] Organization dashboard" issue, with per-group issues only when WATCHDOG_ISSUE_MODE is groups. The scan-step test asserts the new line and the absence of the old one (1 failed, 5 passed against the previous workflow).

CI/CD review of 8 Oct: fail-closed scan (commits 37896d3 and 2151010; current head 2151010)

Review requirement (CI/CD owner, 8 October, on 8ecda44): "Please fail closed for setup/report-generation errors (use guarded commands and robust error handling), and ensure an incomplete scan is explicitly marked BLOCKED/INCOMPLETE rather than published as a clean complete result. Add regression coverage for a failed repository-list generation and a report-generation/enrichment failure; verify the job fails and dashboard reporting never silently treats missing repositories as clean."

Resolved in 37896d3 and 2151010 (two signed-off commits; schedule, default issue mode and decisions.yaml unchanged). Copied onto a checkout of 8ecda44, the new and changed scan and sync tests of 37896d3 fail there (15 failed, 20 passed: 13 new tests, the reworked clone-failure scan test and one adjusted dashboard assertion), and the empty-list test of 2151010 fails there too (the step exits 0); all pass on 2151010. The new guide test covers the WATCHDOG.md section.

An empty or unreadable expected list is INCOMPLETE, never a valid zero-repository scan. An empty repositories: list makes the scan step write an INCOMPLETE summary and exit non-zero; an expected list that is missing, unreadable, not a list or empty makes the issue sync refuse to publish results and exit non-zero.

Requirement Change Covering test
Guarded commands, robust error handling "Scan repositories" runs with set -euo pipefail and an EXIT trap that writes an INCOMPLETE summary and ::error:: on any unexpected stop; clone, rev-parse, watchdog.py, enrichment and the finding total are guarded per repository with if ! or a captured status test_org_scan.py::FailClosed::test_step_runs_with_errexit_and_pipefail
Repository-list generation fails tools/watchdog_scan_support.py list stops the step on failure; expected.json is written before list.txt; an empty list or a list shorter than rollout/repositories.yaml writes "Scan INCOMPLETE: repository list could not be generated", emits ::error:: and exits non-zero test_broken_repository_list_stops_the_scan (broken and missing file), test_short_repository_list_fails_and_missing_repositories_are_blocked
Report-generation and enrichment failure watchdog.py exit or a corrupt report records the repository in blocked.json ("watchdog exit N at ", "report enrichment failed at "), sets the report aside and continues with the next repository test_watchdog_and_enrichment_failures_block_only_their_repository
Incomplete scan marked BLOCKED/INCOMPLETE, job fails After the loop every expected repository without a report or blocked entry is BLOCKED ("no report produced"); the summary heading says COMPLETE only when all were scanned, otherwise "INCOMPLETE: N of M repositories scanned"; the step then exits non-zero; the sync also exits non-zero on any incomplete run, so the job ends red test_scan_reports_every_repository_and_blocks_on_clone_failure, test_watchdog_issue_sync.py::FailClosed::test_command_line_exit_codes
Dashboard never treats missing repositories as clean watchdog_issue_sync.py --expected (passed by the workflow, step keeps if: always()): missing repositories and malformed reports are BLOCKED in both issue modes; the dashboard opens with "Scan INCOMPLETE on : N of M repositories scanned. Results below are partial; missing repositories are listed as BLOCKED and are not clean."; issues and dashboard rows of repositories that were not scanned are never cleared (rows stay as "last known") test_missing_report_is_blocked_with_banner, test_incomplete_run_never_clears_findings_of_unscanned_repositories, test_incomplete_dashboard_keeps_last_known_rows_of_unscanned_repositories, test_malformed_report_is_blocked_not_skipped
Expected list unreadable The sync does not overwrite the dashboard: it posts only an INCOMPLETE notice with the reason (a comment on the existing dashboard, or a banner-only dashboard if none exists) and exits non-zero test_unreadable_expected_list_refuses_to_publish, test_unreadable_expected_list_posts_only_the_banner
Empty or unreadable expected list Scan step: an empty list fails the "list.txt non-empty" check, so the summary says INCOMPLETE and the step exits non-zero. Sync: load_expected rejects a missing, unreadable, non-list or empty expected list; nothing is published as clean and the sync exits non-zero test_org_scan.py::FailClosed::test_empty_repository_list_is_incomplete_not_a_zero_repository_scan, test_unreadable_expected_list_refuses_to_publish (missing file, invalid JSON, [])
Full happy path Summary heading "COMPLETE", no banner, step and sync exit 0 test_org_scan.py::FailClosed::test_happy_path_is_complete_and_passes, test_complete_run_has_no_banner
Documentation WATCHDOG.md "Incomplete scans" (BLOCKED, INCOMPLETE, job red, missing never clean); workflow header comment test_watchdog.py::Guide::test_incomplete_scans_section

Local dry run on 8 October (the real "Scan repositories" step script, real git, fresh clones of the 14 repositories; sync planned without --apply):

# all 14 repositories
## OpenAMRobot Watchdog organization scan: COMPLETE
step exit 0; blocked.json []
Watchdog issue plan (mode dashboard, complete): 0 new, 0 comments, 68 active groups   (sync exit 0)

# openamrobot-comm made unclonable (default_branch: no-such-branch-for-dry-run in a copy of repositories.yaml)
## OpenAMRobot Watchdog organization scan: INCOMPLETE: 13 of 14 repositories scanned
BLOCKED repositories were not scanned and are not clean. The job fails until every repository is scanned.
| openamrobot-comm | BLOCKED: clone failed | not scanned |
::error::Scan INCOMPLETE: 13 of 14 repositories scanned; the summary lists the BLOCKED ones
step exit 1; blocked.json [{"repository": "openamrobot-comm", "reason": "clone failed"}]
Watchdog issue plan (mode dashboard, INCOMPLETE, 13 of 14 repositories scanned): 0 new, 0 comments, 68 active groups   (sync exit 1)
dashboard: **Scan INCOMPLETE on 2026-10-08: 13 of 14 repositories scanned. Results below are partial; missing repositories are listed as BLOCKED and are not clean.**

Evidence

Base SHA: ce39a17
Head SHA: 2151010

GitHub Actions on this head, run https://github.com/openAMRobot/.github/actions/runs/37770189553:

Check Result
quality/test success: PASS: all detected verification stages; register 27 loaded, 23 recorded and scanned, 1 open, 3 superseded
repository-quality / repository-quality (with harness_checks) success
ros-verifier-smoke success
repository-quality / quality/test (opt-in reusable job) skipped, as designed
DCO success
license/cla success

Commands run on this head:

$ python3 tools/check_decisions.py --decisions decisions.yaml --maintainers maintainers.yaml --validate-only
decisions: 27 loaded, 23 recorded and scanned, 1 open, 3 superseded (citations scanned)
$ python3 -m pytest -q tests
236 passed
$ bash rollout/verify.sh
Tests executed: 236 of 236 (skipped 0)   PASS: all detected verification stages
$ python3 tools/watchdog.py --root .
Total: 0 finding(s)   (decisions 0, public extract 0, shared agent rules 0, workflow policy 0, 0 reviews due)
$ python3 tools/check_agent_rules.py --canonical agent-rules/SHARED_RULES.md --file AGENTS.md
PASS AGENTS.md (v2)
$ git ls-files -z '*.sh' | xargs -0 shellcheck   (rollout/verify.sh, the only shell script)
exit 0
$ shellcheck <each bash run: block extracted from .github/workflows/*.yml, ${{ }} replaced>   (14 blocks)
exit 0
$ actionlint                       (all workflows, including watchdog-org-scan.yml with the Europe/Berlin schedule; runs shellcheck on run: blocks)
exit 0

Watchdog scan of every active repository (Round 9, head 4ea9bd4; not re-run in Round 10, which changed issue publication and the schedule only). python3 tools/watchdog.py --root <clone> --report-only ran on fresh --depth 1 clones of the default branch (main) of all 14 repositories in rollout/repositories.yaml, on 7 October 2026, with the Round 9 allowlist. Report only: nothing was enforced, pushed or commented. The .github row is this repository's main; this PR's head scans clean (0 findings). "not run (no AGENTS.md)" means the repository has no AGENTS.md yet (rollout step (a)). Compared with Round 8, public extract fell from 55 to 52: the organisation address in .github profile/README.md and the supplier role addresses sales@ and trade26@ in openamr-platform-hw datasheets/ZDmotor/README.md are now approved; the personal supplier address in datasheets/ZLTech/README.md is still flagged (removed by openamr-platform-hw#17).

Repository Commit Decisions Public extract Shared rules Workflow policy Total Findings per decision or rule
.github (main, not this PR) ce39a17 11 0 1 1 13 RELEASE-MILESTONES 3, COMPUTE 1, LIFT 7, shared-rules 1, unpinned-action 1
openamr-platform-sw 12de3ef 56 15 not run (no AGENTS.md) 3 74 DOCKING-NOT-CHARGING 11, NAV-LIDAR 8, COMPUTE 6, CAMERAS 24, IMU-TOPIC-OWNERSHIP 3, BASE-CONTROLLER-GATES 2, DOCK-NO-CONTACTS 2, price 15, unpinned-action 3
openamr-platform-fw 732f002 3 0 not run (no AGENTS.md) 1 4 BASE-CONTROLLER-IO 1, IMU-TOPIC-OWNERSHIP 1, BASE-CONTROLLER-GATES 1, unpinned-action 1
openamr-platform-hw 169a613 48 20 not run (no AGENTS.md) 1 69 COMPUTE 14, NAV-LIDAR 8, CAMERAS 10, DOCK-NO-CONTACTS 2, RS485-NOT-IN-2-0 6, DRIVETRAIN 2, BASE-CONTROLLER-GATES 4, SAFETY-PROCUREMENT 1, POWER-RAILS 1, price 19, email 1, unpinned-action 1
openamr-upperbody-sw f18c7e2 8 0 not run (no AGENTS.md) 1 9 LIFT 6, MAST-TOP-HEIGHT 2, unpinned-action 1
openamr-upperbody-fw 63c0925 4 0 not run (no AGENTS.md) 1 5 LIFT 4, unpinned-action 1
openamr-upperbody-hw 671b265 8 0 not run (no AGENTS.md) 1 9 LIFT 5, MAST-TOP-HEIGHT 2, MAST-POSITIONS 1, unpinned-action 1
openamrobot-interfaces 7795047 0 0 not run (no AGENTS.md) 3 3 unpinned-action 3
openamrobot-manipulation 795143e 6 0 1 1 8 LIFT 4, MAST-POSITIONS 1, MAST-TOP-HEIGHT 1, shared-rules 1, unpinned-action 1
openamrobot-ui 8b981ad 0 13 1 5 19 price 13, shared-rules 1, unpinned-action 5
openamrobot-comm 1c55292 0 0 not run (no AGENTS.md) 1 1 unpinned-action 1
openamrobot-docs 654078f 48 4 not run (no AGENTS.md) 7 59 MAST-INSTALL-HEIGHT 5, MAST-TOP-HEIGHT 9, NAV-LIDAR 6, MAST-POSITIONS 10, DOCK-NO-CONTACTS 3, LIFT 1, BASE-CONTROLLER-GATES 1, COMPUTE 5, CAMERAS 3, SAFETY-PROCUREMENT 1, RS485-NOT-IN-2-0 1, BATTERY-PLACEMENT 2, BOM-ISSUE-IN-FORCE 1, price 4, unpinned-action 7
openamrobot-manifest 8111c48 0 0 1 3 4 shared-rules 1, unpinned-action 3
openamrobot-release b9f4a9d 1 0 not run (no AGENTS.md) 3 4 COMPUTE 1, unpinned-action 3
Total 193 52 4 32 281

Tests

236 tests, 0 skipped:

Test file Tests
check_decisions 52
check_pr_evidence 45
watchdog_issue_sync (dedup, redaction, reopen, issue mode, fail-closed sync) 24
check_public_extract 19
verify.sh 18
watchdog (runner, guide, accepted words, public contacts, issue mode, incomplete scans) 16
sync_audit_issues 12
org scan (repository list, workflow, schedule, issue-mode variable, fail-closed scan step) 12
reusable workflow (enforce and warn-only, annotation level, checkout depth) 10
watchdog_report (compact format, annotations, job summary, CI isolation) 9
templates 7
check_agent_rules 6
check_workflow_policy 4
line endings 2

Deliberate faults and regressions for the CI/CD review (37896d3, 2151010). The new and changed tests of 37896d3 were copied onto a checkout of 8ecda44: 15 failed, 20 passed. The empty-list test of 2151010 also fails there: AssertionError: 0 == 0, because 8ecda44 finished an empty scan with exit 0. For example, on 8ecda44 a corrupt report for openamrobot-docs was not recorded as BLOCKED ({'repository': 'openamrobot-docs', 'reason': 'report enrichment failed at abc1234'} not found), the summary heading never said INCOMPLETE, and the step ran with set -uo pipefail (no errexit).

Deliberate faults and regressions in Round 10.

Change Result
Issue mode (43f2804) against the previous watchdog_issue_sync.py 13 failed, 3 passed in tests/test_watchdog_issue_sync.py
Default flipped to groups and the dashboard short-circuit removed FAILED test_unset_or_empty_switch_means_dashboard, test_dashboard_mode_plans_no_group_issue_writes, test_dashboard_mode_creates_only_the_dashboard, test_dashboard_mode_updates_the_dashboard_in_place_once, test_command_line_reads_the_switch (5 failed, 11 passed)
Berlin schedule without the test update (0329752) CI run 37700514015: '0 14 * * 4' != '17 6 * * 4' in test_scans_on_thursday_and_writes_only_control_surface_issues, reproduced locally (2 failed, 219 passed); green after 5a8b313

Deliberate faults and regressions in Round 9.

Change Result against the previous code or allowlist
Approved public contacts (172f9c6) against the previous allowlist: FAILED test_approved_public_contacts, FAILED test_organization_allowlist_loads_and_exempts_placeholders (2 failed, 17 passed)
Compact output (48519d5), previous watchdog_report.py FAILED test_grouped_blocks_and_closing_summary, test_distinct_reasons_in_one_group_are_each_printed_once, test_exit_one_on_contradiction, test_finding_explains_decision_why_fix_and_links, test_suite_does_not_leak_into_the_ci_run (5 failed, 56 passed)
Grouped report parsing, previous check_pr_evidence.py FAILED test_contradictions_become_failures, test_long_reports_are_truncated, test_reads_the_real_grouped_checker_output (3 failed, 42 passed)

Deliberate faults and regressions in Round 8.

Change Result before the fix, or with the fault injected
Two unless adjustments (bcbc07a) against the previous register: FAILED test_imu_topic_history_label_is_accepted, FAILED test_legacy_charging_dock_fields_are_accepted (2 failed, 50 passed)
watchdog.py drops the public-extract check FAILED test_all_checks_run_and_summary_groups_by_decision, FAILED test_json_and_markdown_outputs
org scan no longer fails on a BLOCKED clone FAILED test_scan_reports_every_repository_and_blocks_on_clone_failure
Annotation level test_annotation_level_follows_enforcement requires ::error for an enforced pull request and ::warning for warn-only and push scans
Guide drift test_accepted_words_table_matches_register fails when WATCHDOG.md and the register disagree
Test isolation removed from test_check_decisions.py FAILED test_suite_does_not_leak_into_the_ci_run (1 failed, 6 passed); before e75c3b5 a local run with GITHUB_ACTIONS=true printed 2 annotation lines and wrote 353 lines into the job summary

Not verified

  • The Watchdog in GitHub. The organization scan still runs on GitHub only after merge: watchdog-org-scan.yml has not run on GitHub yet (it runs on schedule or manual dispatch only from the default branch, so first after merge); its scan step was run locally with a fake git in the tests, and the real scan above was run locally with the same command. The timezone: "Europe/Berlin" schedule key is accepted by actionlint; the first scheduled run time has not been observed.
  • Fail-closed paths on GitHub. The BLOCKED and INCOMPLETE paths were exercised with the fake-git harness in tests and in the local dry run above; they have not run in GitHub Actions, and the real API calls for the INCOMPLETE banner and notice were tested only with a fake API.
  • Issue publication against the real GitHub API. watchdog_issue_sync.py was exercised only with a fake API in tests. Not verified: that the organization's default token settings allow issues: write and label creation, that assigning BotshareAI succeeds, and how the first dashboard looks on GitHub. With the 8 October dry-run data the dashboard body is 40,855 characters for 68 groups, plus the banner when incomplete; GitHub's limit is 65,536, and there is no truncation guard yet. Inline annotations and the Markdown job summary are covered by unit tests only: this PR's own repository-quality run has 0 findings, so it shows none, and no pull request in another repository has shown them yet. Warn-only mode has not run on GitHub.
  • False-positive review covers the 193 decision findings only. The 52 remaining public-extract findings are 51 prices (never allowlisted) and one personal supplier address; they were not reviewed further. The new allowlist entries were exercised by unit tests and by the local scan of the fresh clones only; no other repository's CI has run them yet.
  • Contributor addresses in CONTRIBUTORS.md, MAINTAINERS.md and maintainers.yaml: none of these files lists an address today, and those files are outside the public-extract scope unless they sit under docs/ or a public path, so that entry is tested with a synthetic file only.
  • Hardware and physical properties. Nothing here validates the lift, its holding behaviour on E-stop or power loss, the CAN3 lift interface, the datum heights, frames or sensor wiring. Register entries are text decisions; those items remain release gates with the platform lead.
  • Source documents. P-03 revisions 18.2 to 18.7 and BOM Issues 7 and 7.3 are not stored in this repository and were not independently read by this run. The register is a textual record supplied for platform-owner reconciliation; physical, electrical and release acceptance remain human gates. The current register declares P-03-rev18.7 (6 October 2026) in force and BOM Issue 7.3.
  • The verify.sh ROS path now runs in a real ros:jazzy-ros-base container against pinned openamrobot-interfaces, with a clean HOME, source-only rosdep scan, generated workspace directories, and both Fast DDS and Cyclone DDS. The unresolved micro_ros_agent key in openamr-platform-sw remains tracked separately in #50.
  • GitHub Actions coverage.
    • The repository-quality workflow now covers the harness itself plus the real ROS verifier smoke described above.
    • pr-assistant, the weekly audit, docs sync and the monthly retro have never run. The last three are designs.
    • The Claude Code action steps were never executed.
  • No failure class is blocked in any other repository. That needs rollout steps (a) to (e) per repository, starting with the openamrobot-interfaces pilot, which has not started.
  • Safety-path approvals are not enforced by this PR. Rulesets and CODEOWNERS must supply them (SETUP.md section 6).
  • Rollout examples: docs-sync.yml contains the literal <HARNESS_SHA> placeholder, and weekly-alignment-audit.yml has one info-level SC2012. Neither is installed anywhere.
  • CODEOWNERS routing for other repositories is a proposal. Write access for the proposed handles was not checked.
  • Repositories outside this session's access (legacy repositories without their own PR template or CONTRIBUTING.md) were not inspected for the effect of the defaults.

Setup required

For the organization owner; details and the (a)/(b)/(c) classification are in rollout/workflows/SETUP.md.

  • Merge, then roll out per repository, openamrobot-interfaces first as the pilot (rollout/README.md):

    • (a) AGENTS.md on shared block v2;
    • (b) pin uses: and harness_ref to the merge SHA;
    • (c) harness_warn: true until a successful run on main;
    • (d) harness_checks: true;
    • (e) require the checks in the ruleset.

    Record the pilot's exit criteria before the next repository starts.

  • Decide when to set WATCHDOG_ISSUE_MODE=groups (platform lead); until then the Watchdog writes only the dashboard issue

  • Replace <HARNESS_SHA> in any workflow copied from rollout/workflows/

  • Secret ANTHROPIC_API_KEY for audits, openamrobot-docs and .github (only when the designs are adopted)

  • Secrets AUDIT_APP_ID / AUDIT_APP_PRIVATE_KEY, DOCS_SYNC_APP_ID / DOCS_SYNC_APP_PRIVATE_KEY, RETRO_APP_ID / RETRO_APP_PRIVATE_KEY

  • Claude GitHub App on audits, openamrobot-docs and .github only; a harness App with Issues read/write, Pull requests read, Contents read/write, Metadata read

  • Actions settings: read-only default token, Actions PR approval off, allow-list the four pinned actions, approval for first-time fork workflows

  • Labels: harness, good first issue, contract-change, audit-finding, blocker, major, area:*

  • Rulesets per repository: PR required, CODEOWNERS review, conversation resolution, required checks once passing on main, no force push

  • Safety paths: two human approvals via ruleset and a CODEOWNERS entry for the platform lead, per the SETUP.md section 6 table

  • Step (a) is still open in openamrobot-manifest, openamrobot-manipulation and openamrobot-ui (shared block v1)

  • Confirm write access for the proposed CODEOWNERS handles before those lines are added in other repositories

  • jq wherever the harness suite runs as evidence (Harness tests: jq is required for the PR-assistant wiring test #42)

  • Resolve the real Jazzy rosdep blocker in openamr-platform-sw#50

  • Complete the AI-workflow activation checklist in .github#43; the workflows remain design-only

Earlier reviews (history)

These reviews were given on earlier heads. GitHub now shows the earlier approvals as dismissed, and none of them covers the current head.

Date Reviewer (role) Head reviewed Outcome
29 Sep panthera-momagdii (software lead) 0b4f332 Changes requested: two fail-open cases in the PR assistant (deleted files, checker errors)
29 Sep KARTHIKEYAN124 (release owner), comment a49c513 ADAPT: rollout order, release-manifest evidence, CODEOWNERS routing
30 Sep KARTHIKEYAN124, comment 12f5210 One remaining change: summary.json write failures must fail the run
30 Sep KARTHIKEYAN124, review beff76e Comments addressed
30 Sep panthera-momagdii beff76e Approved for the software-lead scope (later dismissed)
3 Oct panthera-momagdii 0fa9b64 Adopt for the software-lead scope (later dismissed)
4 Oct anandgawai123456-glitch (documentation owner) 0fa9b64 ADAPT on CONTRIBUTING.md, docs-sync, docs-fix prompt and public-extract policy; no later disposition recorded
6 Oct panthera-momagdii fcf3d8a ADOPT for the software-lead scope (later dismissed)
6 Oct KARTHIKEYAN124, comment fcf3d8a ADOPT for the release scope
6 Oct wikki26 (CI/CD owner) fcf3d8a ADAPT: three verifier issues; staged rollout, zero-test and skip rules, audit design adopted as design or pilot
7 Oct KARTHIKEYAN124 774f2ad ADOPT, approval (later dismissed)
8 Oct panthera-momagdii 8ecda44 Approved for the software-lead scope (later dismissed)
8 Oct KARTHIKEYAN124 8ecda44 Approved for the release-owner scope (later dismissed)
8 Oct wikki26 (CI/CD owner) 8ecda44 ADAPT, changes requested: fail closed in the Watchdog scan; addressed by 37896d3 and 2151010 (mapping above)

The platform lead's source-reconciliation comments on 774f2ad and 8ecda44 are author statements, not approvals. Earlier rounds of this work posted reply and review-gate comments on this pull request; this round posted none and requested no reviews.

Current head state

  • Head: 21510107706bae7893d22c79038529d27ec54e48.
  • CI on this head: green. DCO, license/cla, quality/test, ros-verifier-smoke and repository-quality all succeeded in run 37770189553; the opt-in reusable quality/test job is skipped by design.
  • Approvals given on earlier heads do not carry over to this head. No review has been submitted on this head yet.
  • Still needed on this head: the CI/CD owner's re-review of the fail-closed scan, the software-lead and release-owner reviews, the documentation owner's final disposition (the 4 October ADAPT is still open), and the platform lead's final sign-off.
  • The pull request is marked ready for review. That change was made outside this session; this session did not change the draft or ready state.

Contribution terms

  • No partner, customer or private person is named; the application is Use_Case_1.

AI disclosure

This PR was prepared with Claude Code (AI-assisted). Claude Code helped with repository research,
governance text, workflow/checker implementation, tests and review reconciliation. In Round 8 it wrote the Watchdog output format, tools/watchdog_report.py, tools/watchdog.py, the organization scan workflow, rollout/repositories.yaml, WATCHDOG.md, the register summary and fix_hint texts, the two unless adjustments and their tests, and ran the scans. In Round 9 it wrote the compact output, the approved-contact allowlist entries and their tests, the WATCHDOG.md section, and openamr-platform-hw#17. For the 8 October CI/CD review it wrote the fail-closed scan step, tools/watchdog_scan_support.py, the sync changes, the regression tests and the WATCHDOG.md section, and ran the dry runs. In Round 10 it wrote the issue-mode switch, its tests and documentation, the schedule documentation commit 18d8a2b, performed the sign-off rewrites and wrote this description; the issue publication commits (e87f75a to 5039b53) and the schedule commits (f7c6d96, 5a8b313) were pushed to the branch outside this session and are described from their diffs and messages. A human
reviewer remains responsible for source reconciliation, owner approvals, security decisions,
physical/electrical/safety evidence and merge. The PR adds no new runtime dependency; checker
code uses PyYAML (MIT), and rollout examples reference anthropics/claude-code-action pinned by
commit SHA. No safety implementation is authored or modified here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU

BotshareAI and others added 18 commits September 28, 2026 22:43
…drift check

The shared block now states every rule with its enforcement (gate,
template or named decider), covering sources of record, contracts,
tests, evidence, dependencies, safety, publication, agents, failure
and learning. Internal document links and personal names are removed
from AGENTS.md. check_agent_rules.py reads the marker version from the
canonical file so repositories on v1 fail with a version message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
decisions.yaml holds decided values with source, supersedes history,
applies_to globs, machine checks and an owner role. It is seeded from
P-03 rev18.1, P-00 rev18.1 and the BOM as quoted in the 28 September
alignment audit and from P-03 rev18.2 as cited by the docs site.
maintainers.yaml maps roles to handles, audit prefixes and safety
paths. check_decisions.py validates the schema, scans Markdown, YAML,
launch, URDF/Xacro, package.xml and README files and reports file,
line, found and decided value; tested against a fixture repository.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Fails on Google Drive and Docs links, e-mail addresses, phone numbers,
prices with currency symbols or codes and credential-like strings in
docs/, assets/, README.md and any path containing public. Allowlist
entries need a rule, a match, optional path and repository scope and
a reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
The template carries the sections the checker reads: work package,
Integration Gate, tests, evidence with base and head SHA and commands,
dependencies, safety impact, STATE.md, Not verified and AI disclosure.
The checker fails on missing or empty sections, a test change without
a non-zero reported run, a dependency manifest change without a
Dependencies entry, an unexplained STATE.md, and safety-path changes
without two human reviewers including the platform lead or with AI
authorship. It keeps one summary comment per PR, updated in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Follows openamrobot-interfaces/tools/verify.sh (clean environment, run
directory, result file) and delegates to a repository's own
tools/verify.sh when one exists. Adds project detection, a zero-tests
executed failure, a rule that skip, xfail and importorskip name a
tracking issue, and summary.json evidence with SHAs and test counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
…rkflow

Pull requests check changed files and block. Pushes scan the full
checkout and report warnings; the weekly audit owns the backlog. The
harness ref is an input so callers can pin it with the uses: line.
This repository also runs every checker's tests through verify.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Bug report asks for repository, SHA, exact commands and Not verified.
The interface change request becomes the contract change request and
covers topic names, launch argument names and configuration IDs. New
forms: harness mistake (label harness, feeds the monthly retro) and
good first issue (area, done-when, verify command, reviewer role).
agent-prompts/ holds read-only audit, push from bundle, docs fix and
evaluator pass, each with a precondition block, an expected outcome
and the failure rule. Structural tests cover all of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Plans issues from an audit ISSUES.csv: one issue per Blocker or Major
finding without an issue, in the repository named in file_to_change,
owner from maintainers.yaml by ID prefix; closes open audit issues
whose finding is resolved or absent. Public issues carry only ID,
severity, area, paths and owner handle; full text goes only to the
private fallback repository. Dry run on the 28 September audit plans
82 issues, 45 in public repositories.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
…flows

pr-assistant.yml runs check_decisions.py and check_pr_evidence.py on
the diff under pull_request_target, never executing PR code, and keeps
one summary comment; it never approves or merges. The weekly audit,
docs sync (sender and receiver) and monthly retro run the Claude Code
action pinned to v1.0.236 by commit SHA with restricted tools.
SETUP.md lists secrets, App permissions, labels and branch protection
for the organization owner and states which parts ran here. The
reusable workflow gains an opt-in quality/test job that calls
verify.sh; VERIFY.md documents it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
CONTRIBUTING.md is the contributor path: finding a task, fork and
branch per work package, DCO, the draft PR, what each check verifies,
draft to ready and who reviews what. rollout/README.md gives adoption
order per repository, the release-manifest interaction and the
CODEOWNERS proposal. agent-runs.md records the audit and its follow-ups
with the harness change that now catches each mistake class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
check_decisions.py flagged rollout/README.md for quoting the legacy
compute name as found text; refer to the decision ID instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
decisions.yaml is the register of approved technical decisions; process
stays in AGENTS.md. Each entry now states kind (value, configuration,
limit, exclusion, distinction), scope as repositories and file globs,
provenance, supersession and a verification method: what the text
scan detects and which human reviewer checks what evidence. Adds the
distinction and exclusion entries: 1700 mm is the assembled-height
envelope, no suspension, no RS485, no dock contacts or pilot, no lift,
docking never establishes charging, telemetry is never safety evidence.
P-03 rev18.2 and BOM Issue 7 are recorded as seed evidence only; CI
reads only the pinned register and fetches nothing.

check_decisions.py validates the new fields, detects text that still
cites a superseded source, counts files it did not scan, states that a
clean result is textual consistency only, and never writes. Fixtures
cover a matching value, a contradicting value, an unlisted file type
and a superseded citation. Test strings are synthetic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
The check reports "safety path touched, two human approvals required",
fails only when fewer than two human reviewers (including the platform
lead) are requested, and counts approvals for information. Approvals
themselves are a ruleset requirement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
…tices

Replaces the path-wide vendored-file entry with a line condition: an
e-mail address is allowed only on a licence, copyright or author notice
line, plus the organization contact and placeholders. Handles are not
e-mail addresses. Test URLs are assembled at run time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
sync_audit_issues.py no longer closes issues. For a finding a run no
longer reports, it comments "no longer detected" once and leaves
closure to the owner. Tests use synthetic IDs. Every file under
rollout/workflows states that it is an example or design, not
installed and not run. SETUP.md classifies every check and workflow as
implemented and tested here, rollout example, or human gate, and lists
the per-repository rulesets that supply safety-path approvals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Existing callers reference @main. The decisions, public-extract and
drift steps now run only with harness_checks: true, so merging this
changes nothing in other repositories until each opts in during
rollout. This repository's own caller opts in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
AGENTS.md separates process from the decisions register and adds
"Changing a decision": change request, source document first, one
reviewed PR for register and consumers, owner approval, no tool
rewriting either side. Labels now say check only where a checker
detects the violation, and human with the reviewer and evidence
otherwise. The contract change request form asks for the register
entry and points to that process. CONTRIBUTING.md and the rollout plan
say checks block merges only once installed and required. agent-runs.md
records sanitized failure categories only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Running the check on this PR's own description reported a fixture
package.xml under tests/fixtures as a dependency change. Paths under
fixtures/ or testdata/ are now ignored for the Dependencies rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
BotshareAI and others added 4 commits September 28, 2026 23:27
- decisions.yaml: P-03 rev18.2 is the addendum in force. BOM-ISSUE-IN-FORCE
  is recorded as Issue 7 (P-03 rev18.2 item 7), superseding Issue 6 (P-03
  rev18.1 line 7) and B-01, with checks for Issue 6 or B-01 presented as
  canonical and for citations of the superseded line.
- ROADMAP.md: the 2.0 compute is the Jetson Orin NX on the reComputer
  Robotics J401; the Raspberry Pi is legacy, Gate A only.
- profile/README.md: fixed mast, lift deferred to OpenAMRobot 3.0; the
  imprint uses the organization contact address.
- public-extract-allowlist.yaml: documented entries for the public
  sponsorship tiers in README.md and the robot prices in the profile,
  scoped to this repository and those files.
- maintainers.yaml: ci-owner, release-owner and docs-owner handles left
  empty, filled by the organization owner.
- Tests for the BOM entry and the pricing entries; agent-runs.md and
  SETUP.md updated to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Sets release-owner to KARTHIKEYAN124 as instructed by the platform lead.
ci-owner and docs-owner stay empty until their handles are supplied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
…ity/test

quality/test failed in the lint stage of rollout/verify.sh: the runner
image ships shellcheck, which flagged the unquoted assignment
stage=test (SC2209). The local session had no shellcheck, so the stage
was skipped there. Quote the assignment and install shellcheck in the
job when missing so the lint stage runs the same way everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
…tatus

On the runner (Python 3.12+) unittest exits 5 when no tests run, and the
test stage aborted under set -e before the zero-tests check, so an empty
suite failed as "FAIL: test (exit 5)" instead of "zero tests executed"
and test_zero_tests_fail failed. The stage now records the command's
status, applies the zero-tests rule first, then fails on any non-zero
status. Adds a test that a failing test fails the stage. Checked with
Python 3.11, 3.12 and 3.13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>

@panthera-momagdii panthera-momagdii 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.

Reviewed the software-lead sections: shared agent rules, decisions register, PR assistant/evidence checker and reviewer roles. The overall model is useful and the current repository-quality checks are green, but I found two fail-open cases in the proposed PR assistant that should be fixed before adoption.

  1. rollout/workflows/pr-assistant.yml builds changed.txt with select(.status != "removed"). That means deleted files disappear from check_pr_evidence.py. A PR deleting a dependency manifest or a safety-path file can therefore bypass the dependency/safety-path review rules. Keep all changed filenames for evidence/safety/dependency checks. If check_decisions.py only wants files that still exist in the PR head, use a second filtered list for that checker. Add regression coverage for deletion of a safety-path file and a dependency manifest.

  2. The decision-check step uses set +e, writes only stdout to decisions.txt, prints the exit code, and then continues. check_pr_evidence.py only fails on CONTRADICTION or INVALID decisions file text. If check_decisions.py crashes or exits unexpectedly with no recognized stdout, the PR assistant can still PASS. Capture the exit status explicitly and make any unexpected/non-policy checker failure fail closed. Add a regression for a checker error/exception path.

The pull_request_target design itself is appropriately cautious: trusted harness checkout, PR head treated as data, no PR code execution, and only the repository token is used. The current software-lead reviewer assignments in decisions.yaml for IMU topic ownership, NAV-LIDAR, docking semantics and camera integration are reasonable.

Please fix the two fail-open cases and tag me again.

BotshareAI and others added 2 commits September 29, 2026 17:25
The workflow built changed.txt with select(.status != "removed"), so a PR
that only deleted a dependency manifest or a safety-path file never
reached check_pr_evidence.py. It now writes two lists from the PR files
API: changed_all.txt (every filename, including removed files and the
previous name of a rename) for the evidence, safety-path and dependency
rules, and changed_existing.txt (files present at the PR head) for the
decisions scan only.

Regression tests: deleting a safety-path file and deleting a dependency
manifest are both flagged, and a test runs the workflow's own jq
commands on a sample payload and checks which list each checker gets.
The wiring test fails against the previous workflow.

Reported by the software lead in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
The decisions step ran check_decisions.py under set +e, kept only stdout
and continued; check_pr_evidence.py failed only on CONTRADICTION or
INVALID decisions file lines, so a crash, an empty output or an
unexpected exit code produced PASS.

The workflow now records the exit status in decisions-status.json and
captures stdout and stderr. check_pr_evidence.py takes --decisions-status
and accepts only the two documented outcomes: exit 0 with a clean result
line, and exit 1 with CONTRADICTION lines matching the reported count.
Everything else (traceback, exit 2, any other code, empty output, a
missing or unreadable status or report file) is a checker error: the
summary comment says CHECKER ERROR and the check exits 1.

Regression tests: a real check_decisions.py exception, a synthetic
traceback, non-zero exit with empty output, exit 0 without a result line,
exit 2, mismatched counts, missing status file, missing report file, and
the workflow's own decisions step run with a crashing checker. They fail
against the previous checker, which returned PASS for a crash and for
empty output.

Reported by the software lead in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>

BotshareAI commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

@panthera-momagdii thanks for the review (#38 (review)). I fixed both fail-open cases in new commits; nothing was rebased or squashed.

1. Deleted files bypassed the checks. Fixed in ac95067.

  • rollout/workflows/pr-assistant.yml now writes two lists from the PR files API.
    • changed_all.txt has every changed filename, including removed files and the previous name of a rename. check_pr_evidence.py uses it for the evidence, safety-path and dependency rules.
    • changed_existing.txt has only the files present at the PR head. It is used only by check_decisions.py.
  • Regression tests:
    • A PR that deletes a safety-path file is flagged.
    • A PR that deletes a dependency manifest is flagged.
    • A wiring test runs the workflow's own jq commands on a sample payload (removed safety file, removed package.xml, renamed brake file) and checks which list each checker receives. It fails against the previous workflow.

2. Checker errors passed silently. Fixed in a49c513.

  • The decisions step now captures stdout and stderr and writes the exit status to decisions-status.json.
  • check_pr_evidence.py --decisions-status accepts only the two documented outcomes:
    • exit 0 with a clean result: line;
    • exit 1 with CONTRADICTION lines matching the reported count.
  • Anything else fails closed. The summary comment shows a CHECKER ERROR verdict and the check exits 1. That covers a traceback, exit 2, any other code, empty output, and a missing or unreadable status or report file.
  • Regression tests: a real check_decisions.py exception, non-zero exit with empty output, a missing status file, and the workflow's own decisions step run with a crashing checker, among others. The previous checker returned PASS for a crash and for empty output.

Verification

  • 113 tests pass (39 in the evidence checker's suite), with no skips, on Python 3.11 and 3.12.
  • The drift checker passes on AGENTS.md (v2). actionlint with shellcheck passes on pr-assistant.yml.
  • CI is green on a49c513: https://github.com/openAMRobot/.github/actions/runs/36605060071. pr-assistant.yml itself has still not run on GitHub; its steps were exercised locally.

The PR body's Evidence and What changed sections are updated.


Generated by Claude Code

@KARTHIKEYAN124

Copy link
Copy Markdown
Contributor

Reviewed the release/installation sections at a49c513.

  1. Rollout order — Adapt
    I support repository-by-repository adoption, pinned harness references, and requiring checks only after successful main-branch runs. However, step 1 directs owners to complete SETUP sections 1–4, while SETUP section 1 already enables harness_checks: true. This conflicts with rollout step 2, which requires updating shared rules to v2 first. Please make the prerequisite order consistent. I also recommend completing the interfaces pilot before enabling the harness across all repositories.
  2. Release-manifest interaction — Adapt
    Recording the harness SHA and verification evidence is useful. Please also specify the component commit, package/contract version where applicable, workflow run, and artifact identifier or digest.
    There is an evidence gap: rollout/verify.sh delegates using exec before its summary.json generation. The existing interfaces verifier does not produce that summary, yet the release section expects one from every component. Please define an adapter or explicitly support repository-native evidence, with a test covering delegation.
    Please clarify that a decision-register update affects a pinned consumer only when its harness pin changes or it is explicitly revalidated. Preserve historical release evidence rather than implying it changes retroactively.
  3. CODEOWNERS proposal — Adapt
    The proposal currently has no release-owner entries for manifest, release packaging, or installation documentation. Please add repository-specific routing for those paths, subject to confirmed access.
    Please also clarify that code owners need write access, that the last matching pattern takes precedence, and that listing multiple owners does not require approval from every listed owner.
    These comments concern rollout readiness; they do not request immediate deployment to other repositories.

…pilot

Review by the release and installation owner: SETUP section 1 enabled
harness_checks: true while rollout step 2 required the shared rules v2
first, so the prerequisites contradicted each other.

Per repository the order is now (a) shared rules v2, (b) pin the harness,
(c) warn-only on main until a green run, (d) harness_checks: true,
(e) require the checks in the ruleset. SETUP section 1 no longer enables
the checks; it points to that order.

Step (c) needed a mechanism: the reusable workflow gains harness_warn
(default false), which runs the decisions, public-extract and drift steps
and reports every finding as a warning without failing. harness_checks
stays the enforcing switch and wins if both are set. The check steps take
event, repository and mode from environment variables, and a new test
runs the workflow's own step scripts in both modes.

openamrobot-interfaces is the pilot: it completes (a) to (e) before any
other repository enables the harness, with eight recorded exit criteria
accepted by the CI owner and the release owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPiK6pUmmjNhPceECkKpR2
Signed-off-by: Alex Reznichenko <info@botshare.ai>
BotshareAI and others added 2 commits October 7, 2026 22:59
Exercise the issue-only publisher's PATCH/ comment path and ensure it never
closes issues automatically.

Signed-off-by: Alex Reznichenko <info@botshare.ai>
The repository variable WATCHDOG_ISSUE_MODE selects what the organization
scan writes. Unset or "dashboard" (default): only the single
"[watchdog] Organization dashboard" issue, edited in place when its content
changes, listing every active group with repository, check, group, finding
count, owner and file links. "groups": today's behaviour, one deduplicated
issue per active group plus the dashboard. Scan-blocked repositories always
appear on the dashboard. Any other value stops the sync with exit 2.
The workflow passes vars.WATCHDOG_ISSUE_MODE; WATCHDOG.md explains how to
turn on per-group issues and that the platform lead decides when.
Tests cover both modes and the unset default; with the default flipped to
groups 5 tests fail, against the previous tool 13 fail.

Signed-off-by: Alex Reznichenko <info@botshare.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU
@BotshareAI
BotshareAI force-pushed the claude/brave-hypatia-lv9zbv branch from 2829903 to 43f2804 Compare October 7, 2026 23:03

Copy link
Copy Markdown
Contributor Author

Review-gate refresh — current head 0329752

This head adds the final timezone-aware Watchdog schedule:

on:
  schedule:
    - cron: "0 14 * * 4"
      timezone: "Europe/Berlin"
  workflow_dispatch:

The Watchdog will run every Thursday at 14:00 Berlin time and remains manually dispatchable. No other Watchdog behavior changed.

Please review this exact current head and submit a formal GitHub review:

The earlier Wikki review was an ADAPT/comment disposition on an older head, not a current-head approval. The release-owner approval on 32e3fb8 is also stale. The PR remains draft. Do not merge until current-head reviews, required checks, DCO/CLA and source reconciliation are complete.

BotshareAI and others added 3 commits October 7, 2026 23:13
Signed-off-by: Alex Reznichenko <info@botshare.ai>
Signed-off-by: Alex Reznichenko <info@botshare.ai>
WATCHDOG.md, rollout/workflows/SETUP.md and the workflow header comment now
say the organization scan runs every Thursday at 14:00 Europe/Berlin
(following daylight saving time) plus manual dispatch. SETUP.md also states
that only the dashboard issue is written while WATCHDOG_ISSUE_MODE is unset.

Signed-off-by: Alex Reznichenko <info@botshare.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU
@BotshareAI
BotshareAI force-pushed the claude/brave-hypatia-lv9zbv branch from b562360 to 18d8a2b Compare October 7, 2026 23:14

Copy link
Copy Markdown
Contributor Author

Current-head review gate — 18d8a2b

The current PR head contains the timezone-aware Watchdog schedule and the matching regression-test update:

on:
  schedule:
    - cron: "0 14 * * 4"
      timezone: "Europe/Berlin"
  workflow_dispatch:

Hosted Repository quality run #86 passed on this exact head, including quality/test, repository-quality, and the ROS verifier smoke. Please submit a fresh formal review on 18d8a2b; earlier review dispositions were made on older heads and do not count for this head. The PR remains draft and must not be merged until the current-head review, DCO/CLA, and source-reconciliation gates are satisfied.

The job summary said findings are synchronized to deduplicated issues,
which is wrong in the default dashboard mode. It now says results are
published to the [watchdog] Organization dashboard issue in the harness
repository, with per-group issues only when WATCHDOG_ISSUE_MODE is groups.
The scan-step test asserts the new line and the absence of the old one;
against the previous workflow it fails (1 failed, 5 passed).

Signed-off-by: Alex Reznichenko <info@botshare.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU
@BotshareAI BotshareAI changed the title governance: contribution and agent harness, rules, checks and rollout governance: contribution harness, decisions register and Watchdog Oct 7, 2026
@BotshareAI

Copy link
Copy Markdown
Contributor Author

Platform-lead source reconciliation, head 8ecda44. This is the final head for review. I checked every decisions.yaml entry against P-03 Decision Addendum rev18.7 (6 October 2026), the addendum in force, with BOM Issue 7.3 as the canonical BOM. LIFT, the three superseded mast entries, MAX-ASSEMBLED-HEIGHT, DATUM-HEIGHT-STACK, FRAMES-REP105, BATTERY-PLACEMENT, BASE-CONTROLLER-IO, CAMERAS, HEAD-CAMERA-IDENTITY and BOM-ISSUE-IN-FORCE match rev18.7. NAV-LIDAR (item 13) and RELEASE-MILESTONES (item 12) are unchanged and current. The register checks textual consistency only; it is not mechanical, electrical, safety or release evidence. Merging activates the Watchdog scan (Thursday 14:00 Berlin) in dashboard-only mode, which I accept. As the author, this is my statement, not an approval.

@BotshareAI
BotshareAI marked this pull request as ready for review October 7, 2026 23:50

@panthera-momagdii panthera-momagdii 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.

Software-lead final review on current head 8ecda442f0d7dfcfa4b48b4258386efdb52bd44c: APPROVE for the software-lead scope.

I re-read agent-rules/SHARED_RULES.md and the current decisions.yaml against the current platform baseline. The source-of-truth boundary remains clear: process rules live in the harness, approved technical values live in the register, contract changes stay proposed until owner acceptance, safety/telemetry boundaries remain human-gated, and the earlier deleted-file / fail-closed evidence-check fixes remain intact.

The current register is aligned with the supplied P-03 rev18.7 baseline, including the lift replacing the fixed mast, datum/frame updates, battery placement, STM32H723ZG base-controller I/O, ZED Mini / Gemini camera decisions, RPLIDAR S3 and the release milestones. The checks explicitly claim textual consistency only, not mechanical, electrical, safety or physical acceptance.

I also inspected current-head Repository quality run 37703495722, which is green. GitHub's current Actions documentation supports the IANA timezone field used for the Thursday Europe/Berlin schedule. The installed Watchdog is deterministic/read-only with respect to product repositories and does not activate the AI workflows; #43 remains the separate activation gate.

This approval does not replace the current-head CI/CD, documentation or release-owner reviews and is not an organization-wide rollout or physical-acceptance approval. No merge performed.

KARTHIKEYAN124
KARTHIKEYAN124 previously approved these changes Oct 8, 2026

@KARTHIKEYAN124 KARTHIKEYAN124 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Release-owner review at 0329752: APPROVE / ADOPT for my scope.
I reconfirm the Thursday 14:00 Europe/Berlin Watchdog schedule with manual dispatch, the interfaces-first pilot, staged rollout, matching full-SHA harness pins, and release evidence requirements. Historical evidence remains preserved.
This approval covers 0329752 only. Fresh CI-owner approval, required checks, DCO/CLA, source reconciliation, and final platform-lead sign-off remain separate merge gates.

@wikki26 wikki26 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.

CI/CD owner review — ADAPT / REQUEST CHANGES on head 8ecda44.

I reviewed the Watchdog scan workflow and its reporting/issue-sync integration. Good boundaries: read-only product repository checkouts; only central issues:write; pinned external actions; dashboard-only default; explicit handling of clone failures; tests for issue deduplication and the clone-failure path.

One reliability issue to address before my CI approval:

In .github/workflows/watchdog-org-scan.yml, the "Scan repositories" bash step uses set -uo pipefail (no errexit). Failures in initialization/list generation or in the JSON enrichment, total calculation, and summary-writing commands are not all explicitly checked. For example, if generating $WORK/list.txt fails, the loop can execute zero times, blocked stays 0, and the step can finish successfully. The subsequent if: always() issue-sync step accepts an empty set of reports/blocked records and may replace the dashboard with an apparently empty result. That is not a trustworthy complete 14-repository scan.

Please fail closed for setup/report-generation errors (use guarded commands and robust error handling), and ensure an incomplete scan is explicitly marked BLOCKED/INCOMPLETE rather than published as a clean complete result. Add regression coverage for a failed repository-list generation and a report-generation/enrichment failure; verify the job fails and dashboard reporting never silently treats missing repositories as clean.

This is scoped to the installed Watchdog workflow. I have inspected the code and relevant tests, but have not independently executed the hosted scan or full ROS suite. After this fix and green current-head evidence, I can re-review promptly. I am not authorizing a merge or AI-workflow activation.

Resolves the CI/CD owner review of 8 October on 8ecda44.

Scan step: set -euo pipefail with an EXIT trap that marks any unexpected
stop INCOMPLETE. Repository list generation (tools/watchdog_scan_support.py
list) stops the step on failure, always writes expected.json first, and the
step fails when list.txt is empty or shorter than repositories.yaml. Clone,
rev-parse, watchdog.py, report enrichment and the finding total are guarded
per repository: a failure records the repository in blocked.json with its
reason, sets the report aside and continues. After the loop every expected
repository without a report or blocked entry is BLOCKED as "no report
produced". The summary heading says COMPLETE only when every expected
repository was scanned, otherwise "INCOMPLETE: N of M repositories
scanned", and the job fails.

Issue sync: new --expected (passed by the workflow). Missing repositories
and malformed reports are BLOCKED, never clean; the dashboard opens with the
INCOMPLETE banner; findings and issues of repositories that were not scanned
are never cleared (last known rows stay on the dashboard); an unreadable
expected list posts only an INCOMPLETE notice without overwriting the
dashboard. The sync exits non-zero on any incomplete run.

Tests: 14 new regression tests (scan step with the fake-git harness, sync
planning and API calls); 15 tests fail on 8ecda44. WATCHDOG.md gains an
"Incomplete scans" section; the workflow header comment matches.
Schedule (Thursday 14:00 Europe/Berlin) and default issue mode (dashboard)
are unchanged; no decisions.yaml value changed.

Signed-off-by: Alex Reznichenko <info@botshare.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU
… scan

With repositories: [] the scan step writes an INCOMPLETE summary and exits
non-zero, expected.json is an empty list, and the issue sync treats that
empty expected list as unreadable (exit 1, no clean dashboard). On 8ecda44
the same step exited 0 (assertion 0 == 0).

Signed-off-by: Alex Reznichenko <info@botshare.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DeSLcD827exxSw3xL9zyiU
@BotshareAI

Copy link
Copy Markdown
Contributor Author

Current-head gate, 2151010: the CI/CD review of 8 Oct (fail-closed scan) is addressed. An incomplete or failed scan is now marked BLOCKED/INCOMPLETE, the job fails, and the dashboard never treats missing repositories as clean. The mapping from review requirement to change and test is in the PR description under "CI/CD review of 8 Oct". Approvals on earlier heads do not carry over, so fresh reviews are needed on this head from @wikki26 (CI/CD), @panthera-momagdii (software lead, required for platform-lead-authored PRs), @anandgawai123456-glitch (docs) and @KARTHIKEYAN124 (release).

@panthera-momagdii panthera-momagdii 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.

Fresh software-lead review on current head 21510107706bae7893d22c79038529d27ec54e48: approved for the software-lead scope. Since my prior approval at 8ecda44, the new commits are confined to the Watchdog workflow/support/reporting/tests; agent-rules/SHARED_RULES.md and decisions.yaml are unchanged. The current repository-quality run is green. CI/CD owner re-review of the fail-closed scan remains a separate required gate, along with release/platform sign-off. No merge performed.

@KARTHIKEYAN124 KARTHIKEYAN124 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reconfirm the interfaces-first pilot, staged enforcement, matching full-SHA harness pins, and traceable release evidence. Incomplete scan evidence must not satisfy release acceptance, and historical evidence must remain preserved.
Independent inspection of the current-head changes, regression tests, and hosted checks is still pending, so this comment does not constitute a fresh approval. Earlier approvals do not carry over. Required owner reviews, checks, DCO/CLA, source reconciliation, and platform-lead sign-off remain merge gates.

@wikki26 wikki26 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.

Re-reviewed the updated implementation at commit 2151010.

The changes address my previous fail-open concerns around incomplete organization scans and misleading clean results.

Independent verification completed:

  • Watchdog issue-sync: 24/24 tests passed (Python 3.11).
  • Organization-scan regression tests: 12/12 passed (Ubuntu WSL2, Python 3.12).
  • Confirmed handling of missing/invalid repository lists, incomplete scans, blocked repositories, and preservation of existing findings.

The earlier review concerns are resolved based on the implementation and regression tests. Approved from the CI/CD and quality perspective.

@BotshareAI
BotshareAI merged commit 92e35b0 into main Oct 8, 2026
6 checks passed
@BotshareAI
BotshareAI deleted the claude/brave-hypatia-lv9zbv branch October 8, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants