Skip to content

harness: autonomous improvement loop and decisions.yaml lifecycle (design, off until founder approval on #43) - #70

Draft
BotshareAI wants to merge 2 commits into
mainfrom
harness/autopilot-2026-10-30
Draft

BotshareAI wants to merge 2 commits into
mainfrom
harness/autopilot-2026-10-30

Conversation

@BotshareAI

@BotshareAI BotshareAI commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the harness: 13 always-loaded core rules, 16 skills, 12 missions, 14 behaviour evaluations and deterministic tools that let Claude Code agents improve OpenAMRobot every day, while people keep safety, decisions and merging. The agents' work covers tests, CI preparation, cleanup, PR reviews, and audits of dependencies, contracts, impact, performance, maintainability and the register. It also adds the decisions.yaml lifecycle:

  • every PR declares its Decisions impact;
  • the evidence check asks the author when the diff touches register values;
  • a change request approved by the platform lead becomes a drafted register PR;
  • consumers are updated after the merge.
  • Review fixes (54bdd2b): manual dry-run path, contract coordination, coverage wording, read-only evidence, credential wording; evaluations rerun 14 of 14 at 3 of 3.

Nothing runs after this PR merges: the workflows are design files under rollout/workflows/. Activation needs the founder's explicit approval comment on #43 (D-02), given after this PR is reviewed and merged, the behaviour evaluations pass, and a supervised dry run has been read. Closing #43 is not authorization by itself. harness/README.md is the operating manual.

Work package

#43 (AI workflow activation). Related: #59, #69.

Integration Gate

Builds on #69 (daily collector; triage reads its watchdog-daily artifact); no file overlap with #69. Reuses tools/check_decisions.py (loader, applies_to matching, JSON findings), tools/sync_audit_issues.py (audit issues, one ID range per audit) and agent-prompts/push-from-bundle.md. Inherits the 29 Oct external audit and instruction matrix:

  • register primary, with paired document updates;
  • the E01 to E14 behaviour evaluations as a gate;
  • explicit coverage: 15 repositories enrolled, audits private, and openamr, EOD-robot, OpenAMR_UI_dev and OpenAMR_UI_package excluded by owner decision;
  • an enforcement checklist per repository before write access;
  • no-safe-task as a normal outcome;
  • untrusted-input and model-fidelity rules;
  • manifest Update README.md #8 and platform-sw #101 as owner-led items.

AGENTS.md and CLAUDE.md are unchanged (shared block v2, @AGENTS.md). Rejected:

  • AI review callers in product repositories, because they would need the Claude credential there;
  • a shared-rules version bump now, because it would fail the agent-rules check in 14 repositories before Gate A;
  • the official Claude GitHub App, whose permissions are broader than needed.

Tests

Ran 362 tests, 0 skipped with python3 -m pytest -q tests (278 on the parent). New: tests/test_harness.py, tests/test_harness_publish.py, tests/test_harness_decisions.py. They cover policy, tiers, coverage, the hook, guard, selection, publish validation, artifact boundaries, the review queue, the merge gate, inputs, output scrubbing, decisions impact, the follow-up, register-sync approval, core-rule loading and the eval suite shape. Behaviour evaluations: 14 of 14 cases passed 3 of 3 runs with claude plugin eval on Claude Code 2.1.312 (harness/evals/BASELINE.md; rerun after merge with the pinned model).

Evidence

Base SHA: 71c439e
Head SHA: 54bdd2b
Tree: 016c61c80e3e49f558690b89fa08c328bce79fab

bash rollout/verify.sh
  PASS: all detected verification stages (Tests executed: 362 of 362 (skipped 0))
python3 -m pytest -q tests
  362 passed in 95.07s (0:01:35)
python3 tools/check_workflow_policy.py --root .
  result: 0 workflow policy findings
python3 tools/check_decisions.py --decisions decisions.yaml --maintainers maintainers.yaml --validate-only
  decisions: 39 loaded, 35 recorded and scanned, 1 open, 3 superseded (citations scanned)
python3 tools/check_decisions.py --decisions decisions.yaml --maintainers maintainers.yaml --root . --repository .github --changed-files changed.txt
  result: 0 contradiction(s), 0 allowed, scope 136 changed file(s); 35 file(s) not scanned (no decision covers their type or path)
python3 tools/check_public_extract.py --root . --repository .github --changed-files changed.txt
  result: 0 finding(s)
python3 tools/check_agent_rules.py --canonical agent-rules/SHARED_RULES.md --file AGENTS.md
  PASS AGENTS.md (v2)

changed.txt is git diff --name-only 71c439e3b6dc823589ba2020a7063cf4dce72c13 54bdd2bb253df881901c3daf626acdf1034043a4.

Dependencies

None added to the repository. The design workflows pin by full commit SHA, each verified with git ls-remote against the official repository:

  • anthropics/claude-code-action v1.0.264 8c3fd987fa6a6b2654f69275e323d08207fcd36c (MIT)
  • step-security/harden-runner v2.22.3 46b06cea07f9e64621fdf066ba77ac6915163d43 (Apache-2.0)
  • ros-tooling/setup-ros 0.7.19 649ef6bcd696da05bc27ceb3fab69d810c0daeab (Apache-2.0)
  • actions/checkout v7.0.1 3d3c42e5aac5ba805825da76410c181273ba90b1 (MIT)
  • actions/upload-artifact v7.0.2 cf430e030ddbb5b0abf93d22962f4752f3646cd9 (MIT)
  • actions/download-artifact v8.0.2 9000827ccba6bdab643e8b6fd33ac0654aef8333 (MIT)
  • actions/create-github-app-token v3.3.0 64ab729a6294000f5aa4a4bc0b73d1f32bc45510 (MIT)

Decisions impact

  • None: no register value is stated, used or changed.
  • Consumer: uses or aligns with these entries, unchanged: NEAR-FIELD-FRAMES
  • Change: needs a new or changed decision; change request # (entry: )

Safety impact

The changed files are governance tooling, tests and design workflows in this repository. No robot source, launch file, URDF or collision geometry, motion limit, firmware configuration or interface definition changes, and no changed path matches maintainers.yaml safety_paths (tests/test_harness.py checks this with the evidence check's matching). The harness decides what agents may change on the robot later. So before any activation, two parts need human review: the protected paths and tiers in harness/policy.yaml, and the publish job with its guard.

STATE.md

no change: this repository has no STATE.md (rollout/STATE.md.example only).

Not verified

  • No workflow has run on GitHub; all four are design files or examples.
  • The harden-runner endpoint list is unmeasured; activation starts in audit mode for one week.
  • Artifact download through the API redirect, and the default GITHUB_TOKEN reading other public repositories from Actions.
  • Workload identity federation with the Claude Console (configured by inputs, not exercised).
  • Steps after the agent in the agent job are not a security boundary on hosted runners (sudo). The real boundaries are the publish job's recomputed guard and a short-lived credential. Test counts reported by the agent job are advisory; the PR's own CI is the test gate.
  • Repository rulesets and required checks (enforcement checklist in harness/README.md, confirmed per repository by a person).
  • The Decisions impact rule warns until each repository requires it; tracked in the issue linked below.

AI disclosure

Claude Code drafted and tested every file in a session directed by the platform lead. It ran two independent code review passes and the behaviour evaluations, and fixed every reported defect. This session applied and pushed the prepared change set. A person must read first:

  • harness/policy.yaml (tiers C and D, the register-sync exception, coverage);
  • harness/CORE_RULES.md;
  • harness/claude/hooks/guard_tool.py;
  • tools/harness_guard.py and tools/harness_publish.py;
  • the publish job in rollout/workflows/harness-run.yml;
  • the change to tools/check_pr_evidence.py.

Contribution terms

  • Every commit is signed off under the DCO.
  • I am covered by an accepted Contributor Agreement.
  • Third-party material is identified with source and licence.
  • No confidential, personal, credential or export-controlled information is included.
  • No partner, customer or private person is named; the application is Use_Case_1.

Generated by Claude Code

Harness: policy (tiers A to D, protected paths, blocked commands,
budgets, schedule, missions, escalation, enrolment of 15 repositories,
4 excluded by owner decision, audits private), baseline with the
register-documents sync gate, 13 always-loaded core rules (SessionStart
hook in CI and in the plugin), 16 skills (also a Claude Code plugin),
12 missions, 14 behaviour evaluations for `claude plugin eval` (14 of 14
at 3 of 3 runs), Claude Code settings and a fail-closed PreToolUse hook,
deterministic selection, inputs, guard (recomputed in the publish job
from the bundle), output allowlist with secret scrubbing, publish,
review queue and stage 4 merge gate; design workflows under rollout/.

Decisions lifecycle: Decisions impact section in the PR template and in
check_pr_evidence.py (--decisions, --files-json; warning until
--require-decisions-impact), decision_impact.py, decision_followup.py,
register-sync mission (platform-lead-approved requests only), weekly
register audit in the private audits repository. REG audit prefix owned
by the platform lead.

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

Copy link
Copy Markdown
Contributor Author

Tracking issue for the "Decisions impact rule warns until each repository requires it" item under Not verified: #71


Generated by Claude Code

Review of #70 (adapt):
- Dry run: with HARNESS_PUBLISH unset, a run started by hand runs any
  mission whatever HARNESS_STAGE is and publishes nothing; scheduled AI
  runs are skipped. Stage gates apply only when publishing. Policy gains
  stage 0. Publish steps need HARNESS_PUBLISH=true and the route's
  dry_run=false. The route step is now executed by tests.
- Core rule 5: one approved contract change request drives one PR per
  affected repository, merged in order (interface, consumers, removal).
- Core rule 12 and the digest: excluded repositories are named as
  excluded (out of scope), never as clean or unscanned.
- Core rule 13: the revert test applies to code changes; read-only work
  has its own evidence.
- README: federation credentials are short-lived; an API key is
  spend-limited but long-lived.
- Evaluations rerun with claude-opus-5-5: 14 of 14 at 3 of 3 runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZnPEN4YoUKzMSoLmaZCAS
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 head 50ff826, focusing on policy.yaml, CORE_RULES.md, guard_tool.py, harness_guard.py, harness_publish.py and the publish job. Also checked the merge gate, relevant test coverage and the check_pr_evidence.py diff.

The design-only rollout and separate founder approval on #43 must stay unchanged. This review does not authorize activation.

Requesting changes for three reproducible gaps in the final guard/publish boundary:

  1. Git-quoted filenames bypass the protected-path classification.
  2. Removing an existing assertion still passes as tier A, despite the tier-A no-test-line-removal condition.
  3. A secret-like value committed and then removed is missed by the net-diff scan, although the original commits remain in the bundle and branch that get published.

Inline comments include reproduction details and suggested regression coverage. Please fix these before approval and rerun the guard/publisher tests, including negative cases.

Validation performed: isolated local Git fixtures using byte-verified copies of harness_guard.py and harness_lib.py from this head, with the corresponding path-tier, dependency, mission-exception and safety-path policy entries copied into a test fixture. A safe new test passed and an ordinary protected harness file failed, as expected. All three unsafe fixtures unexpectedly returned PASS. Synthetic secret-pattern text only; no real credentials and no GitHub pushes were used in these tests.

The Repository quality workflow is green. The full upstream 353-test suite and live workflow/agent execution were NOT RUN in this review. No activation, variable changes or merges performed. AI-assisted review.

Comment thread tools/harness_guard.py
Comment on lines +82 to +83
changes = [l.split("\t") for l in git(root, "diff", "--name-status", "--no-renames",
f"{args.base}..HEAD").splitlines() if l]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Parse changed paths with NUL delimiters before applying policy

git diff --name-status quotes paths containing tabs, newlines and, by default, non-ASCII bytes. Splitting the display output leaves the surrounding quotes and escapes in path, so tier_of() is not checking the real pathname. Reproduced with a signed commit adding harness/probe\t.md (a literal tab in the filename): the actual path is tier D, but the guard returns PASS / tier B with files containing the quoted representation. This defeats the publish job's protected-path check even though an ordinary harness/probe.md is correctly rejected.

Use --name-status -z and parse the NUL-delimited status/path records without display quoting. Make diff/stat parsing consistent, or reject unsupported path characters explicitly. Add regression cases for tab, newline and non-ASCII names under protected directories.

Comment thread tools/harness_guard.py
Comment on lines +128 to +132
removed_tests |= test_names(removed)
added_tests |= test_names(added)
lost = sorted(removed_tests - added_tests)
if lost:
failures.append(f"test functions removed: {', '.join(lost[:10])}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Enforce the tier-A restriction on removing existing test lines

Only removed test function names are rejected here. Removing the sole assert from an existing test while keeping its def test_... and a harmless assignment returns PASS / tier A; supplying unchanged before/after executed-test counts also passes. I reproduced that exact case. This violates policy.yaml tier A's condition that no line is removed from an existing test except a rename/move. harness_merge_gate.decide() rechecks file tiers, not this diff condition, so the deterministic gate still treats the weakened test as eligible for stage-4 automatic merge if the other gates pass.

Reject assertion/test weakening and enforce the stated removal rule. At minimum, changes that cannot be demonstrated to be pure renames/moves must not retain tier-A automatic-merge eligibility. Add a regression test that removes an assertion without removing or renaming the test function.

Comment thread tools/harness_guard.py
Comment on lines +123 to +127
for line in added:
if SKIP.search(line) and not ISSUE_REF.search(line):
failures.append(f"{path}: skip or xfail without a tracking issue on the same line: {line.strip()[:120]}")
if SECRET.search(line):
failures.append(f"{path}: secret-like string added")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Validate all history that will be published, not only the final tree diff

per_file comes from the net base..HEAD diff, while the later per-commit loop only checks DCO sign-off. The workflow bundles the original commit range and Publisher.push_bundle() pushes the candidate branch without squashing. Reproduced: commit synthetic text that matches this SECRET regex, then remove it in a second signed commit and add a harmless test. The guard returns PASS / tier A, but the synthetic value is still reachable in the bundle's commit history. The same gap applies to protected-path edits that are reverted before HEAD.

Before publishing, scan every newly reachable commit/blob that will be transferred for secrets and forbidden changes, or reconstruct a fresh commit from the validated net change on the trusted base and publish only that sanitized history. Include an add-then-remove secret fixture and an edit-then-revert protected-path fixture. No real credential was used in this reproduction.

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

Focused security/governance review of #70 at head 50ff826, covering harness/policy.yaml, CORE_RULES.md, the PreToolUse hook, tools/harness_guard.py, tools/harness_publish.py, the publish job in rollout/workflows/harness-run.yml, and the stage-4 merge gate.

[P2] Enforce the selected task's tier ceiling in the deterministic publish guard. harness_select.py sets a selected issue's tier to A or B and harness/missions/build.md calls it a ceiling. The publish job passes it as --max-tier. However, in harness_guard.py, if TIER_ORDER[tier] > TIER_ORDER[args.max_tier] only appends a note, not a failure: a selected tier-A issue can produce a tier-B source change, get guard PASS, and be published as a draft PR. The stage-4 merge gate independently rechecks file tiers, which prevents this from automatically merging, but it does not enforce the earlier one-issue/one-scope authoring boundary. Please add a guard failure when the actual tier exceeds --max-tier, and regression tests for A->B rejection and permitted A->A/B->B. Keep the human escalation path instead of silently upgrading the task scope.

Other boundaries inspected: tier C/D path matching, separate publish-job guard and bundle-base check, bot-author review-marker checks, and stage-4 file-tier recheck. No workflows were activated. I did NOT run the 353-test suite, hook evaluations, supervised dry run, GitHub publish, or hardware; this is source-derived and needs verification before activation. Keep #70 draft, and preserve founder approval on .github issue #43 plus a distinct activation PR. AI-assisted review.

BotshareAI commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor Author

Review fixes pushed in 54bdd2b. All five points accepted.

  1. Dry run. With HARNESS_PUBLISH unset, a run started by hand runs any mission whatever HARNESS_STAGE says and publishes nothing; scheduled AI runs are skipped. Stage gates apply only when publishing. policy.yaml now defines stage 0. Both publish steps need HARNESS_PUBLISH=true and the route's dry_run=false. The route step is executed by tests/test_harness.py::RouteGateTest (triage, build and review at stages 0 and 1 as dry runs; gates enforced when publishing); those tests fail on the previous workflow.
  2. Contracts. Core rule 5 and the contracts skill: one approved contract change request drives one PR per affected repository, each linking the request, merged in order: interface package first and backward compatible, then consumers, then removal of the old form. The shared rules block (AGENTS.md "Contracts") still says "one PR"; that wording goes into shared rules v3 through the retro, since it changes every repository.
  3. Coverage. Core rule 12, policy.yaml and the README: every repository has one disposition (enrolled, private, excluded). Excluded repositories are named as excluded, never as clean or unscanned. The daily digest now ends with a deterministic coverage line (private repositories are never named).
  4. Read-only work. Core rule 13: the revert test applies to code changes; review, audit, analysis and triage change no file and report the files read, the commands run and NOT RUN for the rest.
  5. Credentials. README: federation credentials expire within the hour; a Console API key is spend-limited but long-lived, so rotate it quarterly and revoke it on any suspicion.

Behaviour evaluations rerun after the rule changes, model claude-opus-5-5: 14 of 14 at 3 of 3 runs (harness/evals/BASELINE.md). Tests: 362 passed.

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

Follow-up review of the new head 54bdd2bb253df881901c3daf626acdf1034043a4 against previously reviewed 50ff82690ea3a0987bd00712177c8fb9a554acd9. COMMENT only, not approval or authorization to activate.

The incremental commit addresses the separate governance/dry-run feedback: the manual route now reports dry_run, allows supervised triage/build/review independently of publishing stage, and both publish paths require HARNESS_PUBLISH=true and dry_run=false before --apply. I inspected the changed workflow, policy.yaml, core rules, publish code, route tests, the current hook/guard/merge gate, the shared AGENTS.md rules, and prior review threads. The hosted Repository quality quality/test job 124097061558 passed 362 tests. NOT RUN locally: harness tests, live dry runs, publishing, or activation. The described behaviour is source/CI evidence, not a live deployment test.

The prior security change requests are not resolved by this commit. tools/harness_guard.py is unchanged: the earlier three reproduced P1 findings (Git-quoted protected paths; deletion of an existing assertion still qualifying as tier A; secret/protected edits hidden in earlier commits of the published history) and the P2 tier-ceiling note-versus-failure finding still apply. I am not duplicating their inline reproductions. Please address those checks and add regression coverage before security acceptance.

The AGENTS.md v2 contract wording versus the new one-PR-per-repository core rule is explicitly deferred by the author to shared-rules v3; keep that owner-led reconciliation visible. This is still a design-only draft. No workflow activation without a separate activation PR and Alex's explicit approval on #43, and no automatic-merge or safety acceptance implied.

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

[P1] Require executed successful verification before stage-4 automatic merge.

Reviewed head 54bdd2b. tools/harness_merge_gate.py accepts success, neutral and skipped for every check, and its only nonempty requirement is that check_runs contains an object. I ran decide() with an otherwise eligible tier-A PR, a current-head bot PASS marker, an expired veto window, and exactly one completed/skipped check. It returns [] (no rejection reasons), so the candidate is eligible even though no check succeeded or verified anything.

Please require the repository's authoritative verification checks to execute and succeed, while permitting genuinely optional skipped jobs separately. Add all-skipped, all-neutral, missing-required-verifier, and mixed required-success/optional-skip regression cases. The merge path should also inspect the applicable commit statuses/required contexts; its current check-runs-only read is not independent evidence of CLA or other status-based gates. GitHub rulesets remain another boundary, not a substitute for the stated deterministic gate.

Validation: python3 -m pytest -q tests/test_harness.py tests/test_harness_publish.py tests/test_harness_decisions.py: 84 passed on this head. Standalone decide() reproduction returned []. No merges, publishing, dry-run activation or robot execution. The prior quoted-path, weakened-assertion, hidden-history and tier-ceiling requests remain unresolved in the unchanged guard. Keep design-only/draft and preserve separate founder authorization on #43. OpenAI ChatGPT/Codex-assisted review.

@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/security review for head 54bdd2b (requested by Alex for 2 Nov).

Changes requested — do not activate or treat the green 362-test run as security sign-off. The staged design and separate founder approval on #43 are appropriate, but deterministic guard/publish enforcement still has four release-blocking gaps at this exact head:

  1. Protect actual Git filenames, not quoted display strings (tools/harness_guard.py:56-69,82-93). git diff --name-status (and patch headers) quote tabs/newlines. The current split("\\t")/header parsing can tier a protected harness/ filename as B. Use NUL-delimited raw filenames and path-scoped diff/stat parsing; add tab/newline/non-ASCII protected-path regressions.
  2. Never auto-publish a weakened existing test as tier A (harness_guard.py:117-132). Existing code checks whether the test_* name disappears, not whether its assertions or test lines are removed. Make deletion of a line from an existing test at least tier B / non-auto-merge (or reject it), and add a fixture removing only the sole assertion.
  3. Scan all commits actually pushed (harness_guard.py:117-147, harness_publish.py:201-212). The net base..HEAD scan misses secrets or protected-path edits introduced and then reverted in separate signed commits; publishing the original bundle preserves those objects. Reject unsafe intermediate commits/blobs, or publish only a newly constructed sanitized commit from the independently validated final tree. Test both add/remove synthetic secret and protected-edit/revert fixtures.
  4. Enforce the selected issue tier ceiling (harness_guard.py:106-115). Exceeding --max-tier merely appends a note while returning PASS; the publisher subsequently creates the draft PR. Fail the guard when the final actual tier (including dependency-manifest promotion) exceeds the ceiling. Test A→B rejection, A→A and B→B acceptance.

Please rerun the guard/publisher regression suite and the entire harness verifier on the corrected head, retaining separate HARNESS_PUBLISH=true + dry_run=false authorization and the independent founder/activation PR gate. quality/test currently passes, but the four negative security cases above are not established by its existing tests.

Reviewed: policy tiers/blocked commands, 13 core rules, tool hook, publish workflow and credential separation, guard/publisher and existing unit cases at this SHA. NOT RUN: local Git bypass fixtures, model evaluations, supervised dry run, live publish or hardware. This review is not an activation approval.

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.

3 participants