Skip to content

feat: add guarded php-bin policy consumer - #8

Merged
loadinglucian merged 9 commits into
mainfrom
feat/hybrid-ai
Jul 27, 2026
Merged

feat: add guarded php-bin policy consumer#8
loadinglucian merged 9 commits into
mainfrom
feat/hybrid-ai

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the mise-php side of PLAN-HYBRID-AI.md: commit-pinned php-bin policy capture, evidence-bound planning, offline implementation and repair, deterministic sealing and exact-SHA merge admission, coordinated readiness records, and historical exact-version support.

The review follow-up adds fail-closed evidence path containment, strict plan budgets and types, exact Git argument validation, and broader protected schema ownership.

Verification

  • scripts/test.sh
  • Unsupported-target behavior remains explicit
  • Release selection and checksum behavior are covered by tests
  • The php-bin release contract remains compatible
  • Cross-repository A00–A12 and A14–A20 verifier checks

Security

  • Downloads still require an exact SHA-256 entry
  • No credentials, generated fixtures, or install directories are committed; administrator snapshots retain secret names only
  • Policy synchronization remains bound to exact php-bin policy, invariant, and operator commits

Summary by CodeRabbit

  • New Features

    • Added guarded, evidence-based automation for synchronizing PHP support changes and recording readiness.
    • Added validation tools and schemas for maintenance plans, patches, policy comparisons, and merge checks.
    • Added support for testing and installing end-of-life PHP archives.
  • Bug Fixes

    • PHP installation now accepts only exact stable version formats.
  • Documentation

    • Expanded guidance for automated maintenance, repository settings, recovery, and verification.
  • Security

    • Restricted external network access and pinned workflow actions to immutable revisions.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a guarded PHP maintenance system with policy capture, evidence-bound agent contracts, deterministic patch sealing, validation and repair orchestration, readiness records, exact stable-version checks, repository governance documentation, and supporting tests.

Changes

Guarded maintenance automation

Layer / File(s) Summary
Maintenance contracts and controls
.codex/*, .github/codex/maintenance/*, schemas/*, .github/CODEOWNERS, support-snapshot.json, docs/*
Defines phase controls, JSON contracts, repository governance state, ownership rules, and maintenance artifact directories.
Policy capture and readiness
maintenance/consumer.py, scripts/consume-php-policy
Fetches commit-pinned policy data, compares captured state and events, and emits validated readiness records.
Plan admission and patch sealing
maintenance/admission.py, scripts/admit-maintenance-plan, scripts/seal-maintenance-patch, scripts/verify-merge-admission
Validates evidence, contracts, paths, digests, patch contents, and merge preconditions through CLI commands.
Investigation through readiness workflow
.github/workflows/maintenance-consumer.yml, README.md
Orchestrates investigation, implementation, validation, bounded repair, revalidation, merging, and readiness recording.
Maintenance behavior validation
test/test_maintenance.py
Tests policy comparison, readiness validation, protected paths, pinned URLs, admission, and merge verification.

Exact stable PHP support

Layer / File(s) Summary
Exact stable version installation
lib/releases.lua, hooks/pre_install.lua, scripts/test.sh, test/mock_server.py
Adds exact stable semantic-version validation, applies it during installation, and covers EOL archive packaging and installation in tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Schedule
  participant MaintenanceConsumerWorkflow
  participant Consumer
  participant Admission
  participant Codex
  participant PluginChecks
  participant GitHub

  Schedule->>MaintenanceConsumerWorkflow: trigger scheduled or manual run
  MaintenanceConsumerWorkflow->>Consumer: fetch and compare pinned policy
  Consumer-->>MaintenanceConsumerWorkflow: trigger and action key
  MaintenanceConsumerWorkflow->>Codex: generate evidence-bound investigation plan
  Codex-->>MaintenanceConsumerWorkflow: maintenance plan
  MaintenanceConsumerWorkflow->>Admission: admit plan against contract and digests
  Admission-->>MaintenanceConsumerWorkflow: admitted plan
  MaintenanceConsumerWorkflow->>Codex: implement or repair admitted change
  Codex-->>MaintenanceConsumerWorkflow: implementation result
  MaintenanceConsumerWorkflow->>Admission: seal deterministic patch
  Admission-->>MaintenanceConsumerWorkflow: sealed patch and manifest
  MaintenanceConsumerWorkflow->>PluginChecks: apply patch and run authoritative checks
  PluginChecks-->>MaintenanceConsumerWorkflow: validation result
  MaintenanceConsumerWorkflow->>GitHub: merge validated patch and readiness record
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main guarded php-bin policy consumer addition.
Description check ✅ Passed The description matches the template sections and includes the required verification and security items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hybrid-ai

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (4)
maintenance/admission.py (1)

309-323: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Parse git path output with -z to avoid quoted-path mismatches.

--name-only and ls-files quote non-ASCII/special paths ("\303\251.txt") unless -z is used, so those entries won't match the real filesystem path and sealing fails with a misleading "unsupported diff entry". Fail-closed, but confusing.

♻️ Proposed refactor
-    changed = subprocess.run(
-        ["git", "diff", "--name-only", "--diff-filter=ACDMRTUXB", base, "--"],
+    changed = subprocess.run(
+        ["git", "-c", "core.quotePath=false", "diff", "-z", "--name-only", "--diff-filter=ACDMRTUXB", base, "--"],
         cwd=repo,
         check=True,
         text=True,
         stdout=subprocess.PIPE,
-    ).stdout.splitlines()
-    untracked = subprocess.run(
-        ["git", "ls-files", "--others", "--exclude-standard"],
+    ).stdout.split("\0")
+    untracked = subprocess.run(
+        ["git", "ls-files", "-z", "--others", "--exclude-standard"],
         cwd=repo,
         check=True,
         text=True,
         stdout=subprocess.PIPE,
-    ).stdout.splitlines()
-    paths = sorted(set(changed + untracked))
+    ).stdout.split("\0")
+    paths = sorted({item for item in changed + untracked if item})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintenance/admission.py` around lines 309 - 323, Update the git path
collection in the changed and untracked subprocess calls to use NUL-delimited
output via the appropriate -z options, then parse stdout by NUL separators
instead of splitlines(). Preserve the existing filtering, path combination, and
sorting behavior so non-ASCII and special filenames match their real filesystem
paths.
.github/workflows/maintenance-consumer.yml (1)

63-70: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Move ${{ }} expansions into env: for the run blocks.

zizmor flags the inline expansions; these values are validated upstream so this isn't exploitable today, but binding them via env: removes the whole class and keeps the interpolation out of the shell parse. Same pattern applies to the other inline expansions in run steps in this file.

♻️ Proposed refactor
       - name: Prepare exact investigation contract
         if: steps.compare.outputs.trigger != 'quiet' && steps.operator.outputs.state == 'enabled'
+        env:
+          OPERATOR_COMMIT: ${{ steps.operator.outputs.commit }}
+          OPERATOR_STATE: ${{ steps.operator.outputs.state }}
         run: |
           jq -n \
             ...
-            --arg phpBinOperatorCommit "${{ steps.operator.outputs.commit }}" \
-            --arg operatorState "${{ steps.operator.outputs.state }}" \
+            --arg phpBinOperatorCommit "$OPERATOR_COMMIT" \
+            --arg operatorState "$OPERATOR_STATE" \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maintenance-consumer.yml around lines 63 - 70, Move all
GitHub Actions `${{ }}` expressions used inside `run` steps in the maintenance
workflow into step-level `env:` entries, including the values currently passed
to jq arguments such as operator commit and state. Update the shell commands to
reference the corresponding environment variables, preserving existing names and
behavior while removing inline expression interpolation from shell parsing.

Source: Linters/SAST tools

test/test_maintenance.py (2)

64-69: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

protected() test only covers 4 of 11 protected globs.

PROTECTED in maintenance/admission.py guards 11 path patterns (.codex/*, schemas/*, .github/CODEOWNERS, the three named admission scripts, etc.), but this test only exercises .github/workflows/*, maintenance/*, maintenance-events/*, and readiness/*. Given the PR's fail-closed guarantee for these control-plane paths, a regression silently dropping an entry from PROTECTED (e.g. the admission script names) wouldn't be caught here.

♻️ Suggested additional coverage
     def test_protected_controls_are_not_admissible(self):
         self.assertTrue(protected(".github/workflows/maintenance.yml"))
         self.assertTrue(protected("maintenance/admission.py"))
         self.assertTrue(protected("maintenance-events/new-patch.json"))
         self.assertTrue(protected("readiness/new-branch.json"))
+        self.assertTrue(protected(".codex/implementation.config.toml"))
+        self.assertTrue(protected("schemas/maintenance-plan.schema.json"))
+        self.assertTrue(protected(".github/codex/maintenance/shared.md"))
+        self.assertTrue(protected(".github/CODEOWNERS"))
+        self.assertTrue(protected("scripts/admit-maintenance-plan"))
+        self.assertTrue(protected("scripts/seal-maintenance-patch"))
+        self.assertTrue(protected("scripts/verify-merge-admission"))
         self.assertFalse(protected("lib/releases.lua"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_maintenance.py` around lines 64 - 69, Expand
test_protected_controls_are_not_admissible to cover every path pattern defined
by PROTECTED in the protected() implementation, including .codex/*, schemas/*,
.github/CODEOWNERS, and each explicitly named admission script, while retaining
the existing positive and negative assertions.

51-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the expected consumer failure type.

readiness(... "main" ...) and pinned_policy_urls("main") raise ConsumerError, but these assertions currently catch bare Exception. Catch ConsumerError instead so unrelated regressions don’t satisfy the expected failure path. Also import ConsumerError from maintenance.consumer.

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

In `@test/test_maintenance.py` around lines 51 - 62, Update
test_readiness_requires_exact_commits_and_digests to import ConsumerError from
maintenance.consumer and assert that the invalid readiness call raises
ConsumerError instead of the broad Exception type, preserving the existing
failure scenario.

Source: Linters/SAST tools

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

Inline comments:
In @.github/CODEOWNERS:
- Line 9: Add an explicit CODEOWNERS entry for scripts/consume-php-policy,
assigning the same maintenance policy owners as the related control-path wrapper
so changes require the appropriate review.

In @.github/workflows/maintenance-consumer.yml:
- Around line 458-459: Update the gh pr create invocation in the maintenance
workflow so the --body value contains actual newline characters rather than
literal \n text. Preserve the existing title and body content, using the shell’s
supported multiline or escape-expansion mechanism.
- Around line 424-425: Update the job condition associated with the push/merge
step to use !cancelled() instead of always(), while preserving the existing
validation success requirements involving needs.validate.outputs.passed and
needs['validate-repair'].result.
- Around line 508-515: Replace the hardcoded success written to
maintenance-run/checks.json in the maintenance workflow with the real PR
check-results data already used by the jq -e enforcement step. Ensure the
generated JSON preserves each check’s actual status so verify-merge-admission
can reject non-success results, while keeping the existing verifier invocation
unchanged.

In `@lib/releases.lua`:
- Around line 55-58: Update M.is_exact_stable_version so each version component
rejects leading-zero forms while still accepting 0 and non-zero-leading
integers, including the optional hyphenated suffix. Add regression tests
covering padded components such as 08.01.001 and valid canonical stable
versions.

In `@maintenance/admission.py`:
- Around line 344-345: Update the secret-detection regex in the admission check
around the `re.search` call to use a regex word-boundary escape for the `sk-`
token pattern, rather than matching a literal backslash and `b`. Preserve the
existing private-key and `github_pat_` detection alternatives.
- Around line 211-218: Update the evidence validation around evidence_refs so
completeness requires every captured policy to be cited exactly once, not merely
matching the count. Reject duplicate captureId values and ensure the resulting
unique references cover all keys in captures_by_id while preserving the existing
digest validation.
- Around line 140-146: Update the admission logic for the action validation
block and downstream edit-bound checks so a valid “no_change” plan terminates
quietly before requiring editsRequired or support-snapshot.json in allowedPaths.
Preserve rejection of blocked and needs_human plans, and keep all other accepted
actions subject to the existing admission requirements.

In `@maintenance/consumer.py`:
- Around line 190-218: Update the policy validation around maintainedBranches,
sourceEvidenceDigests, actionKey, and acceptedAt to require string values before
passing them to re.fullmatch; ensure malformed JSON types, including numeric
list entries or non-string scalar fields, raise the existing ConsumerError
instead of TypeError. Preserve the current format, ordering, and policy-action
validations after type checks.

In `@schemas/agent-completion-assessment.schema.json`:
- Around line 4-12: Harden the control-plane schemas: in
schemas/agent-completion-assessment.schema.json (lines 4-12), validate
instruction digest fields and enforce that goNoGo "go" requires phaseStatus
"complete" with no unresolved items; in schemas/agent-task-contract.schema.json
(lines 4-14), require non-empty, correctly typed authority, criteria, non-goal,
and stop-condition values; in schemas/maintenance-plan.schema.json (lines
10-29), require exactly one non-empty evidence record for each of the four
distinct evidence types.

---

Nitpick comments:
In @.github/workflows/maintenance-consumer.yml:
- Around line 63-70: Move all GitHub Actions `${{ }}` expressions used inside
`run` steps in the maintenance workflow into step-level `env:` entries,
including the values currently passed to jq arguments such as operator commit
and state. Update the shell commands to reference the corresponding environment
variables, preserving existing names and behavior while removing inline
expression interpolation from shell parsing.

In `@maintenance/admission.py`:
- Around line 309-323: Update the git path collection in the changed and
untracked subprocess calls to use NUL-delimited output via the appropriate -z
options, then parse stdout by NUL separators instead of splitlines(). Preserve
the existing filtering, path combination, and sorting behavior so non-ASCII and
special filenames match their real filesystem paths.

In `@test/test_maintenance.py`:
- Around line 64-69: Expand test_protected_controls_are_not_admissible to cover
every path pattern defined by PROTECTED in the protected() implementation,
including .codex/*, schemas/*, .github/CODEOWNERS, and each explicitly named
admission script, while retaining the existing positive and negative assertions.
- Around line 51-62: Update test_readiness_requires_exact_commits_and_digests to
import ConsumerError from maintenance.consumer and assert that the invalid
readiness call raises ConsumerError instead of the broad Exception type,
preserving the existing failure scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 60bc9323-49ca-435a-bcb5-e6afd297c285

📥 Commits

Reviewing files that changed from the base of the PR and between ed08878 and 7bc055c.

📒 Files selected for processing (33)
  • .codex/implementation.config.toml
  • .codex/investigation.config.toml
  • .codex/repair.config.toml
  • .github/CODEOWNERS
  • .github/codex/maintenance/implementation.md
  • .github/codex/maintenance/investigation.md
  • .github/codex/maintenance/repair.md
  • .github/codex/maintenance/shared.md
  • .github/workflows/ci.yml
  • .github/workflows/e2e.yml
  • .github/workflows/maintenance-consumer.yml
  • .gitignore
  • README.md
  • docs/admin-state/mise-php-before.json
  • docs/repository-settings.md
  • hooks/pre_install.lua
  • lib/releases.lua
  • maintenance-events/.gitkeep
  • maintenance/__init__.py
  • maintenance/admission.py
  • maintenance/consumer.py
  • readiness/.gitkeep
  • schemas/agent-completion-assessment.schema.json
  • schemas/agent-task-contract.schema.json
  • schemas/maintenance-plan.schema.json
  • scripts/admit-maintenance-plan
  • scripts/consume-php-policy
  • scripts/seal-maintenance-patch
  • scripts/test.sh
  • scripts/verify-merge-admission
  • support-snapshot.json
  • test/mock_server.py
  • test/test_maintenance.py

Comment thread .github/CODEOWNERS
/schemas/ @loadinglucian
/scripts/admit-maintenance-plan @loadinglucian
/scripts/seal-maintenance-patch @loadinglucian
/scripts/verify-merge-admission @loadinglucian

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Protect the policy-consumer entrypoint.

scripts/consume-php-policy is currently unmatched, so it can be altered without the CODEOWNER review applied to maintenance/. Add an explicit ownership rule for this control-path wrapper.

Proposed fix
 /scripts/verify-merge-admission `@loadinglucian`
+/scripts/consume-php-policy `@loadinglucian`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/scripts/verify-merge-admission @loadinglucian
/scripts/verify-merge-admission `@loadinglucian`
/scripts/consume-php-policy `@loadinglucian`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/CODEOWNERS at line 9, Add an explicit CODEOWNERS entry for
scripts/consume-php-policy, assigning the same maintenance policy owners as the
related control-path wrapper so changes require the appropriate review.

Comment on lines +424 to +425
needs: [investigate, validate, validate-repair]
if: always() && (needs.validate.outputs.passed == 'true' || needs['validate-repair'].result == 'success')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Use !cancelled() rather than always() on a job that pushes and merges.

always() keeps this job running when the workflow run is cancelled, so a cancelled run can still push a branch and merge a PR.

🐛 Proposed fix
-    if: always() && (needs.validate.outputs.passed == 'true' || needs['validate-repair'].result == 'success')
+    if: ${{ !cancelled() && needs.investigate.result == 'success' && (needs.validate.outputs.passed == 'true' || needs['validate-repair'].result == 'success') }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
needs: [investigate, validate, validate-repair]
if: always() && (needs.validate.outputs.passed == 'true' || needs['validate-repair'].result == 'success')
needs: [investigate, validate, validate-repair]
if: ${{ !cancelled() && needs.investigate.result == 'success' && (needs.validate.outputs.passed == 'true' || needs['validate-repair'].result == 'success') }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maintenance-consumer.yml around lines 424 - 425, Update
the job condition associated with the push/merge step to use !cancelled()
instead of always(), while preserving the existing validation success
requirements involving needs.validate.outputs.passed and
needs['validate-repair'].result.

Comment on lines +458 to +459
url="$(gh pr create --base main --head "$branch" --title "chore: $action_key" \
--body "Deterministically sealed mise-php maintenance patch.\n\nValidated commit: \`$validated\`.")"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

\n is not interpreted inside double quotes; the PR body renders literal \n.

🐛 Proposed fix
-            url="$(gh pr create --base main --head "$branch" --title "chore: $action_key" \
-              --body "Deterministically sealed mise-php maintenance patch.\n\nValidated commit: \`$validated\`.")"
+            url="$(gh pr create --base main --head "$branch" --title "chore: $action_key" \
+              --body "$(printf 'Deterministically sealed mise-php maintenance patch.\n\nValidated commit: `%s`.' "$validated")")"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
url="$(gh pr create --base main --head "$branch" --title "chore: $action_key" \
--body "Deterministically sealed mise-php maintenance patch.\n\nValidated commit: \`$validated\`.")"
url="$(gh pr create --base main --head "$branch" --title "chore: $action_key" \
--body "$(printf 'Deterministically sealed mise-php maintenance patch.\n\nValidated commit: `%s`.' "$validated")")"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maintenance-consumer.yml around lines 458 - 459, Update
the gh pr create invocation in the maintenance workflow so the --body value
contains actual newline characters rather than literal \n text. Preserve the
existing title and body content, using the shell’s supported multiline or
escape-expansion mechanism.

Comment on lines +508 to +515
jq -n '{"Plugin contract":"success"}' > maintenance-run/checks.json
./scripts/verify-merge-admission \
--repo . \
--head "$expected" \
--manifest maintenance-run/sealed/patch-manifest.json \
--checks maintenance-run/checks.json \
--preconditions maintenance-run/preconditions.json \
--current maintenance-run/current.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Derive checks.json from the real PR check results instead of hardcoding success.

verify_merge rejects when any check value is not "success" (maintenance/admission.py line 427), but the input is synthesized as a constant here, so that gate can never fire. The actual enforcement only lives in the jq -e on line 470; feed the same data to the verifier.

♻️ Proposed fix
-          jq -n '{"Plugin contract":"success"}' > maintenance-run/checks.json
+          jq '[.[] | {key: .name, value: (if .bucket == "pass" then "success" else .bucket end)}] | from_entries' \
+            maintenance-run/pr-checks.json > maintenance-run/checks.json
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jq -n '{"Plugin contract":"success"}' > maintenance-run/checks.json
./scripts/verify-merge-admission \
--repo . \
--head "$expected" \
--manifest maintenance-run/sealed/patch-manifest.json \
--checks maintenance-run/checks.json \
--preconditions maintenance-run/preconditions.json \
--current maintenance-run/current.json
jq '[.[] | {key: .name, value: (if .bucket == "pass" then "success" else .bucket end)}] | from_entries' \
maintenance-run/pr-checks.json > maintenance-run/checks.json
./scripts/verify-merge-admission \
--repo . \
--head "$expected" \
--manifest maintenance-run/sealed/patch-manifest.json \
--checks maintenance-run/checks.json \
--preconditions maintenance-run/preconditions.json \
--current maintenance-run/current.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/maintenance-consumer.yml around lines 508 - 515, Replace
the hardcoded success written to maintenance-run/checks.json in the maintenance
workflow with the real PR check-results data already used by the jq -e
enforcement step. Ensure the generated JSON preserves each check’s actual status
so verify-merge-admission can reject non-success results, while keeping the
existing verifier invocation unchanged.

Comment thread lib/releases.lua
Comment on lines +55 to +58
function M.is_exact_stable_version(version)
return version:match("^%d+%.%d+%.%d+$") ~= nil
or version:match("^%d+%.%d+%.%d+%-[1-9]%d*$") ~= nil
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate releases.lua =="
fd -a 'releases\.lua$' . | sed 's#^\./##'

echo "== git diff stat =="
git diff --stat || true

echo "== inspect file outline and relevant lines =="
if [ -f lib/releases.lua ]; then
  wc -l lib/releases.lua
  ast-grep outline lib/releases.lua || true
  echo "== lines 1-140 =="
  sed -n '1,140p' lib/releases.lua | nl -ba
fi

echo "== search is_exact_stable_version usages =="
rg -n "is_exact_stable_version|find|release|stable_version|match\\^%d+\\.%" . || true

Repository: Bigpixelrocket/mise-php

Length of output: 399


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate version parsing in relevant files =="
rg -n "is_exact_stable_version|find.*version|release_lookup|GetLatest|GetRelease|match\\^%d|VERSION" . \
  -g '!*.png' -g '!*.jpg' -g '!*.gif' || true

echo "== Focus Lua parser/version behavior from config files =="
fd -i '.*\\.(toml|json|lua|sh|m4|ac)$' . | head -200 | sed -n '1,160p'

Repository: Bigpixelrocket/mise-php

Length of output: 1203


🌐 Web query:

mise-php Bigpixelrocket releases.lua is_exact_stable_version version patterns

💡 Result:

The terms mentioned, such as "Bigpixelrocket," "releases.lua," "is_exact_stable_version," and specific "version patterns," do not appear to be standard components of the official core mise project (formerly asdf-rust) [1][2] or the common verzly/mise-php plugin [3][4]. Based on the available evidence: 1. Bigpixelrocket: This name appears in license files for specific community projects (e.g., laravel-omakase and laravel-mise) [5][6], but it is not a recognized maintainer or component of the primary mise CLI or its standard PHP plugins [4]. 2. Releases.lua, is_exact_stable_version, and version patterns: These do not exist as public-facing configurations or internal APIs in the official mise codebase [1][2] or the verzly/mise-php repository [3][4]. Version resolution in mise is generally handled through its core backend logic [2], which supports automatic detection of tags (optionally handling "v" prefixes) [2] rather than user-defined Lua scripts or specific "is_exact_stable_version" flags [1]. If you are encountering these terms, they are likely part of a specific, private, or experimental wrapper or plugin unrelated to the standard ecosystem. You may wish to check the specific repository where you encountered these files for custom documentation or README.md files, as they are not standard to mise itself.

Citations:


🌐 Web query:

Bigpixelrocket Bigpixelrocket/mise-php releases.lua is_exact_stable_version

💡 Result:

There is no official or commonly referenced code, file, or function named is_exact_stable_version associated with a repository named Bigpixelrocket/mise-php. The primary plugin for managing PHP versions within the mise tool is verzly/mise-php [1]. Research indicates that Bigpixelrocket is a separate entity/handle associated with other projects, such as laravel-omakase, but is not the maintainer of the standard PHP plugin for mise [2][3]. Furthermore, the term is_exact_stable_version does not appear in the public source code or documentation for the mise tool or its common PHP plugins [4][1][5][6]. It is possible that the query refers to internal logic within a specific, non-standard, or private repository, or perhaps a misunderstanding of mise's internal mechanisms, which prioritize version resolution based on tags or definitions provided in the plugin's metadata [1]. If you are encountering this term in a specific script or configuration, it may be a custom-defined variable or function within that local environment rather than part of the mise-php ecosystem.

Citations:


🌐 Web query:

"Bigpixelrocket" "lib/releases.lua" "is_exact_stable_version" "8.1.99"

💡 Result:

Based on the available information, there is no widely recognized or authoritative technical library or project known as "Bigpixelrocket" that contains a lib/releases.lua file with a function named is_exact_stable_version. The term "Bigpixelrocket" appears to be associated with a small graphic design agency [1] and has been identified as a vendor namespace in certain PHP/Laravel-related projects [2][3], but it is not a known source for Lua-based versioning utilities. Publicly available Lua versioning tools, such as kikito/semver.lua [4] or Akionka/lua-semver [5], use standard Semantic Versioning (SemVer) practices but do not feature a function specifically named is_exact_stable_version in a lib/releases.lua file. Similarly, general scripts named releases.lua exist in various open-source projects (e.g., pixie-io/pixie [6] or ColumPaget/releases.lua [7]), but they do not appear to match the specific query parameters provided. It is possible that this function exists within a private or highly specific internal codebase not indexed by public search engines.

Citations:


🌐 Web query:

"8.4.99" "php-bin" "bigpixelrocket" release tags

💡 Result:

There is no known software release, package, or technical identifier corresponding to "8.4.99 php-bin bigpixelrocket". Research indicates that "Bigpixelrocket" is a small graphic design agency [1], and while it is associated with developers (such as those managing projects like "deployer-php" or "laravel-mise" on GitHub [2][3][4]), there is no evidence linking the entity to a product named "php-bin" or a version "8.4.99". "php-bin" is a common name for repositories providing pre-compiled PHP binaries (often used by projects like NativePHP [5], phpacker [6][7], or Cecil [8]), but these projects are distinct from Bigpixelrocket. Furthermore, PHP 8.4 versions are currently in the 8.4.x series (e.g., 8.4.12, 8.4.20) [9][8], and "8.4.99" is not a standard release tag for any PHP-related binary project. It is likely that this query conflates unrelated terms.

Citations:


🌐 Web query:

"lib/releases.lua" "55-58" "is_exact_stable_version" "version:match"

💡 Result:

The phrase "is_exact_stable_version" paired with "version:match" does not appear to be part of a single, widely recognized standard library or public Lua project. Based on a search of common Lua repositories, these terms are likely specific to a private or project-specific implementation of version management. In the context of Lua version handling: 1. Version Matching Logic: Projects like kong/version.lua [1][2] and kikito/semver.lua [3] use match methods as part of their object-oriented APIs to determine if a version satisfies a range or condition. The version:match pattern is common in these libraries, where a version object (or range object) is evaluated against another string or object. 2. Implementation Examples: Other tools, such as toolchainlib (using Luau), utilize version:match with variant-like patterns to branch logic based on whether a version is provided (Some/None) [4]. 3. Semantic Versioning: If you are looking for code responsible for parsing and matching versions, you should verify if your project relies on one of the common Lua semantic versioning libraries mentioned above, which handle version string parsing via string.match internally [5][3]. If lib/releases.lua is a file in a specific repository you are working with, it is highly probable that is_exact_stable_version is a helper function defined within that file to restrict matching to stable releases (e.g., excluding pre-releases like -alpha or -beta tags) by using version:match to validate the version's format or to compare it against a strict pattern [5][6]. You may find the exact implementation by examining that specific file's source code.

Citations:


🌐 Web query:

GitHub "Bigpixelrocket" "mise-php" "test/mock_server.py"

💡 Result:

There is no public GitHub repository or project named Bigpixelrocket/mise-php, and no file path matching test/mock_server.py exists within any known context for such a project [1][2][3]. It is possible that the query refers to a private repository, a misremembered name, or a conflation of several different projects: 1. PHP plugins for mise: The most prominent mise plugins for PHP are verzly/mise-php [1][2] and tobiashochguertel/mise-php-plugin [3]. 2. Mock servers in testing: Files named mock_server.py are common in many open-source projects for testing purposes [4][5][6], but none are associated with a "Bigpixelrocket" project. 3. Laravel-related packages: There is a separate package associated with the handle "bigpixelrocket" called laravel-omakase [7], but it is unrelated to mise or a mock server of that name. If you are looking for a specific testing script for mise-related development, you may be thinking of the official mise repository, which includes a tool_stub_test_server.py file used for end-to-end testing [4].

Citations:


🌐 Web query:

"lib/releases.lua" "\"08.01.001\" \"%d+%.%d+%.%d+\""

💡 Result:

The string "08.01.001" and the Lua pattern "%d+%.%d+%.%d+" are frequently used in Lua programming for version parsing and validation [1][2]. In Lua, the pattern "%d+%.%d+%.%d+" is a common way to match semantic version strings [2][3]. The components work as follows: - %d+: Matches one or more digits [2]. - %.: Matches a literal dot character (the % escapes the special meaning of the dot in Lua patterns) [2][3]. While there is no single authoritative library named "lib/releases.lua" that defines these globally, many projects use files named releases.lua to handle versioning, release metadata, or registry synchronization [4][5][6][7][8]. In such contexts, code typically utilizes string.match or string.find with this pattern to validate or extract version numbers from strings like "08.01.001" [2][9][3]. For example, a typical implementation might look like this: local version = "08.01.001" local match = string.match(version, "%d+%.%d+%.%d+") if match then print("Valid version format: ".. match) end This approach is standard for parsing version identifiers in Lua, leveraging the language's built-in pattern-matching library [2][9].

Citations:


Enforce canonical version components.

%d+ accepts zero-padded versions such as 08.01.001, so malformed stable versions can pass the “exact stable” gate before release lookup. Validate each component as 0 or a non-zero-leading integer, and add regression tests.

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

In `@lib/releases.lua` around lines 55 - 58, Update M.is_exact_stable_version so
each version component rejects leading-zero forms while still accepting 0 and
non-zero-leading integers, including the optional hyphenated suffix. Add
regression tests covering padded components such as 08.01.001 and valid
canonical stable versions.

Comment thread maintenance/admission.py
Comment on lines +140 to +146
if plan.get("action") not in {
"no_change", "new_patch", "new_branch", "branch_eol", "repair",
"reconcile_partial", "blocked", "needs_human",
}:
raise AdmissionError("invalid maintenance action")
if plan.get("action") in {"blocked", "needs_human"}:
raise AdmissionError("no-go plan cannot advance")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

no_change is an accepted action but can never be admitted.

Line 241 requires editsRequired is True and line 263 requires support-snapshot.json in allowedPaths, so any no_change plan is rejected with a hard error rather than terminating quietly. The workflow's edits_required output is only consulted after admission, so a legitimate no-change conclusion fails the scheduled run. Either drop no_change from the accepted set or short-circuit it before the edit-bound checks.

♻️ Sketch
-    if plan.get("action") in {"blocked", "needs_human"}:
+    if plan.get("action") in {"blocked", "needs_human"}:
         raise AdmissionError("no-go plan cannot advance")
+    if plan.get("action") == "no_change":
+        return {
+            "admitted": True,
+            "actionKey": plan.get("actionKey", ""),
+            "planDigest": digest_bytes(canonical(plan)),
+            "instructionDigests": {},
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if plan.get("action") not in {
"no_change", "new_patch", "new_branch", "branch_eol", "repair",
"reconcile_partial", "blocked", "needs_human",
}:
raise AdmissionError("invalid maintenance action")
if plan.get("action") in {"blocked", "needs_human"}:
raise AdmissionError("no-go plan cannot advance")
if plan.get("action") not in {
"no_change", "new_patch", "new_branch", "branch_eol", "repair",
"reconcile_partial", "blocked", "needs_human",
}:
raise AdmissionError("invalid maintenance action")
if plan.get("action") in {"blocked", "needs_human"}:
raise AdmissionError("no-go plan cannot advance")
if plan.get("action") == "no_change":
return {
"admitted": True,
"actionKey": plan.get("actionKey", ""),
"planDigest": digest_bytes(canonical(plan)),
"instructionDigests": {},
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintenance/admission.py` around lines 140 - 146, Update the admission logic
for the action validation block and downstream edit-bound checks so a valid
“no_change” plan terminates quietly before requiring editsRequired or
support-snapshot.json in allowedPaths. Preserve rejection of blocked and
needs_human plans, and keep all other accepted actions subject to the existing
admission requirements.

Comment thread maintenance/admission.py
Comment on lines +211 to +218
evidence = plan.get("evidence", [])
if not isinstance(evidence, list) or len(evidence) != len(captures_by_id):
raise AdmissionError("plan does not cite the complete captured policy set")
evidence_refs = set()
for index, item in enumerate(evidence):
capture = captures_by_id.get(item.get("captureId")) if isinstance(item, dict) else None
if capture is None or item.get("digest") != capture.get("digest"):
raise AdmissionError("plan evidence does not match the captured policy")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Evidence completeness check can be satisfied by duplicate citations.

len(evidence) != len(captures_by_id) only enforces a count. Four entries all citing support_policy pass, so the plan need not cite all four captures despite the error message claiming completeness.

🔒 Proposed fix
     evidence = plan.get("evidence", [])
     if not isinstance(evidence, list) or len(evidence) != len(captures_by_id):
         raise AdmissionError("plan does not cite the complete captured policy set")
+    cited = {item.get("captureId") for item in evidence if isinstance(item, dict)}
+    if cited != set(captures_by_id):
+        raise AdmissionError("plan does not cite each captured policy exactly once")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
evidence = plan.get("evidence", [])
if not isinstance(evidence, list) or len(evidence) != len(captures_by_id):
raise AdmissionError("plan does not cite the complete captured policy set")
evidence_refs = set()
for index, item in enumerate(evidence):
capture = captures_by_id.get(item.get("captureId")) if isinstance(item, dict) else None
if capture is None or item.get("digest") != capture.get("digest"):
raise AdmissionError("plan evidence does not match the captured policy")
evidence = plan.get("evidence", [])
if not isinstance(evidence, list) or len(evidence) != len(captures_by_id):
raise AdmissionError("plan does not cite the complete captured policy set")
cited = {item.get("captureId") for item in evidence if isinstance(item, dict)}
if cited != set(captures_by_id):
raise AdmissionError("plan does not cite each captured policy exactly once")
evidence_refs = set()
for index, item in enumerate(evidence):
capture = captures_by_id.get(item.get("captureId")) if isinstance(item, dict) else None
if capture is None or item.get("digest") != capture.get("digest"):
raise AdmissionError("plan evidence does not match the captured policy")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintenance/admission.py` around lines 211 - 218, Update the evidence
validation around evidence_refs so completeness requires every captured policy
to be cited exactly once, not merely matching the count. Reject duplicate
captureId values and ensure the resulting unique references cover all keys in
captures_by_id while preserving the existing digest validation.

Comment thread maintenance/admission.py
Comment on lines +344 to +345
if re.search(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|github_pat_|\\bsk-[A-Za-z0-9_-]{20,}", text):
raise AdmissionError(f"secret-like material in diff: {path}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

\\b in the raw-string regex is a literal backslash, disabling the sk- token check.

In a raw string \\b matches a backslash followed by b, not a word boundary, so sk-… keys are only detected when literally preceded by \. Use \b.

🔒 Proposed fix
-        if re.search(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|github_pat_|\\bsk-[A-Za-z0-9_-]{20,}", text):
+        if re.search(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|github_pat_|\bsk-[A-Za-z0-9_-]{20,}", text):
             raise AdmissionError(f"secret-like material in diff: {path}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if re.search(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|github_pat_|\\bsk-[A-Za-z0-9_-]{20,}", text):
raise AdmissionError(f"secret-like material in diff: {path}")
if re.search(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|github_pat_|\bsk-[A-Za-z0-9_-]{20,}", text):
raise AdmissionError(f"secret-like material in diff: {path}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintenance/admission.py` around lines 344 - 345, Update the secret-detection
regex in the admission check around the `re.search` call to use a regex
word-boundary escape for the `sk-` token pattern, rather than matching a literal
backslash and `b`. Preserve the existing private-key and `github_pat_` detection
alternatives.

Comment thread maintenance/consumer.py
Comment on lines +190 to +218
branches = policy_document.get("maintainedBranches")
if not (
isinstance(branches, list)
and all(re.fullmatch(r"\d+\.\d+", value) for value in branches)
and branches == sorted(set(branches), key=lambda value: tuple(map(int, value.split("."))))
):
raise ConsumerError("captured php-bin branches are invalid or non-canonical")
evidence = policy_document.get("sourceEvidenceDigests")
if not (
isinstance(evidence, list)
and all(re.fullmatch(r"sha256:[0-9a-f]{64}", value) for value in evidence)
and evidence == sorted(set(evidence))
):
raise ConsumerError("captured php-bin support evidence is invalid or non-canonical")
policy_action = policy_document.get("actionKey")
if not (
policy_action == "bootstrap"
or re.fullmatch(
r"(?:new_branch:\d+\.\d+|branch_eol:\d+\.\d+:\d{4}-\d{2}-\d{2})",
policy_action or "",
)
):
raise ConsumerError("captured php-bin support action key is invalid")
if policy_action != "bootstrap" and not evidence:
raise ConsumerError("captured php-bin support policy lacks accepted evidence")
if not re.fullmatch(
r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", policy_document.get("acceptedAt", "")
):
raise ConsumerError("captured php-bin support acceptance time is invalid")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Validate JSON value types before regex matching.

A malformed value such as maintainedBranches: [1] raises TypeError in re.fullmatch() and escapes the controlled rejection path. Require strings for branch, evidence, action-key, and timestamp fields before matching.

Proposed fix
-        and all(re.fullmatch(r"\d+\.\d+", value) for value in branches)
+        and all(isinstance(value, str) and re.fullmatch(r"\d+\.\d+", value) for value in branches)
...
-        and all(re.fullmatch(r"sha256:[0-9a-f]{64}", value) for value in evidence)
+        and all(isinstance(value, str) and re.fullmatch(r"sha256:[0-9a-f]{64}", value) for value in evidence)
...
-    if not re.fullmatch(
-        r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", policy_document.get("acceptedAt", "")
-    ):
+    accepted_at = policy_document.get("acceptedAt")
+    if not isinstance(accepted_at, str) or not re.fullmatch(
+        r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", accepted_at
+    ):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintenance/consumer.py` around lines 190 - 218, Update the policy validation
around maintainedBranches, sourceEvidenceDigests, actionKey, and acceptedAt to
require string values before passing them to re.fullmatch; ensure malformed JSON
types, including numeric list entries or non-string scalar fields, raise the
existing ConsumerError instead of TypeError. Preserve the current format,
ordering, and policy-action validations after type checks.

Comment on lines +4 to +12
"required": ["contractVersion", "instructionDigests", "phaseStatus", "criteria", "goNoGo", "unresolved", "summary"],
"properties": {
"contractVersion": {"const": 1},
"instructionDigests": {"type": "object"},
"phaseStatus": {"enum": ["complete", "blocked", "needs_human"]},
"criteria": {"type": "array"},
"goNoGo": {"enum": ["go", "no_go"]},
"unresolved": {"type": "array"},
"summary": {"type": "string"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Harden the control-plane schemas before relying on them as admission gates.

The schemas enforce field presence more than semantic validity, allowing contradictory completion states, vacuous agent contracts, and incomplete evidence sets.

  • schemas/agent-completion-assessment.schema.json#L4-L12: validate digest fields and require GO to imply a complete phase with no unresolved work.
  • schemas/agent-task-contract.schema.json#L4-L14: require non-empty, typed authority, criteria, non-goal, and stop-condition values.
  • schemas/maintenance-plan.schema.json#L10-L29: require all four distinct evidence records exactly once.
📍 Affects 3 files
  • schemas/agent-completion-assessment.schema.json#L4-L12 (this comment)
  • schemas/agent-task-contract.schema.json#L4-L14
  • schemas/maintenance-plan.schema.json#L10-L29
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@schemas/agent-completion-assessment.schema.json` around lines 4 - 12, Harden
the control-plane schemas: in schemas/agent-completion-assessment.schema.json
(lines 4-12), validate instruction digest fields and enforce that goNoGo "go"
requires phaseStatus "complete" with no unresolved items; in
schemas/agent-task-contract.schema.json (lines 4-14), require non-empty,
correctly typed authority, criteria, non-goal, and stop-condition values; in
schemas/maintenance-plan.schema.json (lines 10-29), require exactly one
non-empty evidence record for each of the four distinct evidence types.

@loadinglucian
loadinglucian merged commit 5842a17 into main Jul 27, 2026
2 checks passed
@loadinglucian
loadinglucian deleted the feat/hybrid-ai branch July 27, 2026 09:04
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.

1 participant