From 6bb0d991098cb70a8f3e0df09a5a9424b867117f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 17:27:21 +0900 Subject: [PATCH 1/2] feat(automation): run psychometrics-commons hourly NVIDIA NIM review repair Add a thin minute-9 caller so hosted measurement pull requests receive the same exact-head RCA repair heartbeat as other CWL products without copying scheduler, model, or credential logic. --- .../hourly-nvidia-nim-review-repair.yml | 7 + ...hometrics-commons-hourly-review-repair.yml | 35 ++++ AGENTS.md | 1 + ARCHITECTURE.md | 2 +- CHANGELOG.md | 12 ++ ...chometrics-commons-hourly-review-caller.md | 160 ++++++++++++++++ ...chometrics_commons_hourly_review_caller.py | 178 ++++++++++++++++++ 7 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/psychometrics-commons-hourly-review-repair.yml create mode 100644 docs/doctoring/psychometrics-commons-hourly-review-caller.md create mode 100644 tests/test_psychometrics_commons_hourly_review_caller.py diff --git a/.github/workflows/hourly-nvidia-nim-review-repair.yml b/.github/workflows/hourly-nvidia-nim-review-repair.yml index 702942708..dc5beb05c 100644 --- a/.github/workflows/hourly-nvidia-nim-review-repair.yml +++ b/.github/workflows/hourly-nvidia-nim-review-repair.yml @@ -16,6 +16,7 @@ on: - .github/workflows/nonnest2-hourly-review-repair.yml - .github/workflows/originweave-hourly-review-repair.yml - .github/workflows/quarantine-sandbox-hourly-review-repair.yml + - .github/workflows/psychometrics-commons-hourly-review-repair.yml - scripts/ci/pr_review_conflict_scope.py - scripts/ci/pr_review_autofix_context.py - tests/test_bandscope_hourly_review_caller.py @@ -27,6 +28,7 @@ on: - tests/test_nonnest2_hourly_review_caller.py - tests/test_originweave_hourly_review_caller.py - tests/test_quarantine_sandbox_hourly_review_caller.py + - tests/test_psychometrics_commons_hourly_review_caller.py - tests/test_hourly_autofix_context_quality_gate.py - tests/test_pr_review_conflict_scope.py - tests/test_pr_review_conflict_scope_control_files.py @@ -51,6 +53,7 @@ on: - docs/doctoring/nonnest2-hourly-review-caller.md - docs/doctoring/originweave-hourly-review-caller.md - docs/doctoring/quarantine-sandbox-hourly-review-caller.md + - docs/doctoring/psychometrics-commons-hourly-review-caller.md push: paths: - .github/workflows/pr-review-fix-scheduler.yml @@ -66,6 +69,7 @@ on: - .github/workflows/nonnest2-hourly-review-repair.yml - .github/workflows/originweave-hourly-review-repair.yml - .github/workflows/quarantine-sandbox-hourly-review-repair.yml + - .github/workflows/psychometrics-commons-hourly-review-repair.yml - scripts/ci/pr_review_conflict_scope.py - scripts/ci/pr_review_autofix_context.py - tests/test_bandscope_hourly_review_caller.py @@ -77,6 +81,7 @@ on: - tests/test_nonnest2_hourly_review_caller.py - tests/test_originweave_hourly_review_caller.py - tests/test_quarantine_sandbox_hourly_review_caller.py + - tests/test_psychometrics_commons_hourly_review_caller.py - tests/test_hourly_autofix_context_quality_gate.py - tests/test_pr_review_conflict_scope.py - tests/test_pr_review_conflict_scope_control_files.py @@ -101,6 +106,7 @@ on: - docs/doctoring/nonnest2-hourly-review-caller.md - docs/doctoring/originweave-hourly-review-caller.md - docs/doctoring/quarantine-sandbox-hourly-review-caller.md + - docs/doctoring/psychometrics-commons-hourly-review-caller.md permissions: contents: read @@ -157,6 +163,7 @@ jobs: tests/test_nonnest2_hourly_review_caller.py \ tests/test_originweave_hourly_review_caller.py \ tests/test_quarantine_sandbox_hourly_review_caller.py \ + tests/test_psychometrics_commons_hourly_review_caller.py \ tests/test_pr_review_conflict_scope_control_files.py \ tests/test_hourly_autofix_context_quality_gate.py \ tests/test_pr_review_conflict_scope_git_executable.py \ diff --git a/.github/workflows/psychometrics-commons-hourly-review-repair.yml b/.github/workflows/psychometrics-commons-hourly-review-repair.yml new file mode 100644 index 000000000..a26e60416 --- /dev/null +++ b/.github/workflows/psychometrics-commons-hourly-review-repair.yml @@ -0,0 +1,35 @@ +name: psychometrics-commons Hourly Review Repair + +on: + schedule: + # Minute 9 avoids pg-llm-batch (1), aFIPC (2), kaefa (3), LineageWeave (4), + # codec-carver (5), life-os (6), Wardnet (7), mightyETL (8), naruon (11), + # pg-erd-cloud (13), orchestrator (17), noema (19), Clearfolio (23), + # Keyverse (29), Scopeweave (31), DiskSage (37), Appguardrail (41), + # newsdom-api (43), Inkspan (47), fast-mlsirm (49), BandScope (53), + # and semantic-data-portal (59). + - cron: "9 * * * *" + +concurrency: + group: psychometrics-commons-hourly-review-repair + # A later heartbeat must not cancel an in-flight measurement or consent RCA. + cancel-in-progress: false + +permissions: + contents: read + +jobs: + dispatch-review-repair: + permissions: + contents: read + id-token: write + uses: ./.github/workflows/pr-review-fix-scheduler.yml + with: + target_repository: ContextualWisdomLab/psychometrics-commons + base_branch: main + max_prs: "50" + max_dispatches: "1" + retry_hours: "2" + secrets: + PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index bd6a96a11..7eb3dc820 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,3 +7,4 @@ Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include ( Conflict-scope roots fail closed when the immediate parent directory is a symbolic link. OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md). nonnest2 hourly NVIDIA NIM repair is a thin caller at minute 16. See [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md). +psychometrics-commons hourly NVIDIA NIM repair is a thin caller at minute 9. See [`docs/doctoring/psychometrics-commons-hourly-review-caller.md`](docs/doctoring/psychometrics-commons-hourly-review-caller.md). diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3e2e70b58..a9e792300 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -123,4 +123,4 @@ trusted `uv` exporter is downloaded from the literal GitHub Releases URL for - [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md) — current increment's repair-worker decision and APA 7th citations. - [`docs/doctoring/fast-mlsirm-hourly-review-caller.md`](docs/doctoring/fast-mlsirm-hourly-review-caller.md) - — product-specific psychometric repair heartbeat and scientific gates. \ No newline at end of file + — product-specific psychometric repair heartbeat and scientific gates. diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1aebf43..abd456c64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Semantic Versioning where the repository publishes a release. - Added a dedicated Quarantine Sandbox Runtime hourly caller at minute 14 that targets protected `develop`, dispatches at most one exact-head repair, applies a two-hour same-head retry floor, preserves non-cancelling single-flight execution, and maps only the established scheduler credentials with job-scoped OIDC. - Added a dedicated Quarantine Sandbox Runtime hourly caller at minute 14 that targets protected `develop`, dispatches at most one exact-head repair, applies a two-hour same-head retry floor, preserves non-cancelling single-flight execution, and maps only the established scheduler credentials with job-scoped OIDC. - Added a dedicated OriginWeave hourly caller that invokes the product-neutral central scheduler with the exact repository, protected `main` branch, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, job-scoped OIDC, and only the established scheduler credentials. +- Added a dedicated psychometrics-commons hourly caller that invokes the product-neutral central scheduler with the exact repository, protected `main` branch, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, job-scoped OIDC, and only the established scheduler credentials. - Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate. - Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence. - Added a permanent exact-head contract workflow for the hourly review-repair scheduler, immutable reusable-workflow source, NVIDIA NIM model boundary, credential isolation, and fail-closed unattended-agent permissions. @@ -39,6 +40,13 @@ Semantic Versioning where the repository publishes a release. - Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109). - Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109). - Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories. +- Run the bounded psychometrics-commons repair heartbeat at minute 9 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening measurement-governance, consent-ledger, or scientific-recovery gates. +- Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603` with explicit high reasoning for scheduled repair and `nvidia/nemotron-3-nano-30b-a3b` for bounded helper work instead of GitHub Models in the write-capable autofix worker. +- Apply one NUL-delimited exact-path and complete pre/post-worktree verification contract to both ordinary review repair and merge-conflict repair rather than relying on a visible post-model diff for the ordinary path. + +### Fixed + +- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context. - Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367). - Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. - Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed. @@ -60,6 +68,7 @@ Semantic Versioning where the repository publishes a release. - Keep the Clearfolio caller and reusable scheduler read-only at workflow and job scope; authorize mutation only through explicitly mapped `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, or the short-lived OpenCode GitHub App token exchanged from OIDC, with explicit pre-write guards and no `github.token` mutation fallback. - Keep the DiskSage caller read-only and pass only the established scheduler credentials; do not inherit secrets, expose the NVIDIA NIM model credential to the queue scanner, use a GitHub Copilot token, or grant the caller repository mutation permissions. - Keep the fast-mlsirm caller read-only and model-secret-free; preserve independent approval, exact-head evidence, and Rust production-arithmetic ownership while centralizing only bounded review repair. +- Keep the psychometrics-commons caller read-only and model-secret-free; preserve independent approval, exact-head evidence, measurement-governance gates, and operational participant evidence without adding a PII mask. - Bind `NVIDIA_NIM_API_KEY` only to the two OpenCode model execution steps, fail closed when the secret is absent, and remove GitHub and Actions OIDC credentials from both model subprocesses. The decision record now cites CWE-367 so a later default-branch push cannot replace privileged repair helpers after `repository_dispatch` has already selected the workflow revision. - Recorded the org control-plane architecture, including the hourly NVIDIA NIM repair gate, so agents reconstruct the write-capable worker trust boundary from the repo instead of private memory. - Deny unnecessary non-file OpenCode interactions and preserve the independent read-only reviewer workflow and its credential/model-pool contract byte-for-byte. @@ -75,3 +84,6 @@ Semantic Versioning where the repository publishes a release. - Added fast-mlsirm operational documentation for the hourly RCA loop, psychometric scientific gates, Rust ownership, bounded retry cadence, credential isolation, modular reuse, rollback, and APA 7 references. - Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. - Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. +- Added psychometrics-commons operational documentation for the hourly RCA loop, measurement and consent gates, bounded retry cadence, credential isolation, modular reuse, rollback, and APA 7 references. +- Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. +- Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. \ No newline at end of file diff --git a/docs/doctoring/psychometrics-commons-hourly-review-caller.md b/docs/doctoring/psychometrics-commons-hourly-review-caller.md new file mode 100644 index 000000000..f2d2eadcf --- /dev/null +++ b/docs/doctoring/psychometrics-commons-hourly-review-caller.md @@ -0,0 +1,160 @@ +# psychometrics-commons hourly review-repair caller + +검토 기준일: **2026-08-17** + +## Decision + +ContextualWisdomLab operates one protected hourly caller for +`ContextualWisdomLab/psychometrics-commons` (headless public psychometric +assessment, reflective self-understanding, longitudinal observation, and +consent-governed research contribution). The caller runs at minute 9, +delegates to the product-neutral central review-fix scheduler, inspects +at most 50 open pull requests targeting protected `main`, and dispatches +at most one bounded repair per heartbeat. + +A paying buyer of hosted measurement would feel live psychometrics-commons +pull requests stalling while hourly NVIDIA NIM repair scanned only +Clearfolio, DiskSage, and fast-mlsirm. Live heads such as +ContextualWisdomLab/psychometrics-commons#244 (data-rights access binding), +ContextualWisdomLab/psychometrics-commons#242 (append-only purpose-bound +audit evidence), ContextualWisdomLab/psychometrics-commons#240 (fail-closed +license evidence), and ContextualWisdomLab/psychometrics-commons#237 +(anonymous participant base identity) target `main` and never enter those +other callers. + +The caller does not implement review or mutation logic itself. +psychometrics-commons remains standalone; naruon, fast-mlsirm, aFIPC, +kaefa, and other CWL services consume measurement contracts without owning +the hosted product runtime. Privileged automation stays in +`ContextualWisdomLab/.github`. + +## Root-cause analysis and remediation feasibility + +The reusable worker performs exact-head root-cause analysis and tests +remediation feasibility before it edits. The reusable worker must: + +1. Refetch the exact live head, base, reviews, checks, changed paths, and + writer state. +2. Establish the causal chain rather than repeat the terminal symptom. +3. Enumerate materially distinct minimal remedies. +4. Reject remedies that lack writer authority, cross sealed paths, require + unavailable credentials or protected-setting changes, violate stack + order, cannot be verified, or do not alter the diagnosed cause. +5. Dispatch at most one feasible repair. Otherwise leave the tree + unchanged. + +A queued or pending check remains a merge blocker but is not itself a +code finding. The independent non-author approval remains an external +authorization gate and is never synthesized by the repair worker. The +worker cannot approve, merge, release, resolve review findings by +inference, change protection, or manufacture passing checks. + +Psychometric publication bounds, true-parameter recovery, DIF/invariance, +multilevel and temporal validity, skipped-test prohibitions, and Rust +ownership of production arithmetic in `fast-mlsirm` are not loosened to +make a check green. A recovery or scoring-dispatch failure requires +scientific and numerical root-cause analysis rather than threshold +inflation. Operational participant identifiers, consent ledgers, and +audit evidence stay visible under access control; the caller adds no +operational-PII mask. + +## Cadence and concurrency + +The caller uses a single concurrency group and `cancel-in-progress: false`. +This preserves an in-flight bounded RCA instead of discarding measurement +or consent evidence when the next hourly heartbeat arrives. The reusable +scheduler cancels only its own superseded short queue scan. + +The caller sets a **two-hour same-head retry floor**. Central OpenCode and +NVIDIA NIM work, plus scoring-job or consent-ledger analysis, can +legitimately approach two hours. An hourly redispatch of the same +unchanged head would create duplicate writer pressure rather than faster +remediation. + +GitHub scheduled workflows can be delayed under load and execute only +from the default branch. The cron expression is a heartbeat, not a +real-time SLA. + +## Credential and model boundary + +The caller keeps workflow `GITHUB_TOKEN` at `contents: read` and grants +the reusable job `id-token: write` so the central scheduler can mint the +OpenCode GitHub App token from GitHub OIDC when the mapped PAT is absent +(GitHub, n.d.-c). It maps only `PR_REVIEW_MERGE_TOKEN` and +`OPENCODE_APPROVE_TOKEN`. It never uses `secrets: inherit`, receives +`NVIDIA_NIM_API_KEY`, or introduces `COPILOT_GITHUB_TOKEN`. CWE-250 +forbids executing the caller with write or model privileges it does not +need (MITRE, 2026). + +Model execution remains inside the central worker. The model credential +is the GitHub Secret `NVIDIA_NIM_API_KEY`; the caller does not receive or +forward it. + +Before protected-main activation, the repository variable +`OPENCODE_REPOSITORY_DISPATCH_TARGETS` must contain the exact +`ContextualWisdomLab/psychometrics-commons` target. Missing or mismatched +configuration fails before mutation credential materialization. + +## Security, standalone operation, and modularity + +The caller adds no psychometrics-commons runtime dependency, database +object, network endpoint, tenant authority, or product credential. +psychometrics-commons continues to run as a standalone hosted measurement +product. Naruon and other CWL services may consume its contracts, but +they cannot weaken its exact-head, approval, scientific, CSAP/SOC 2 +readiness, or security gates. + +## Verification and rollback + +Machine-checkable contracts require the exact target/base, minute 9 +cadence, non-cancelling single-flight group, one dispatch, two-hour +retry floor, explicit secret mapping, read-only contents plus job-scoped +`id-token: write`, focused path-filter coverage, and absence of model or +Copilot credentials. Independent `pull_request`, `push`, and `compileall` +path blocks must each name the caller, doctoring, or contract they own. + +After source integration, closure requires a scheduled or manual +protected-main consumer run proving the exact psychometrics-commons +repository and `main` base. Source checks alone are not +protected-main operational acceptance. +Merge still requires zero unresolved valid findings and a +qualifying independent non-author approval. + +Rollback removes the psychometrics-commons caller, its focused test, +doctoring, and central path-filter/documentation entries. It must not +remove scheduler dispatch validation or affect independent product +callers. + +## APA 7th references + +American Educational Research Association, American Psychological +Association, & National Council on Measurement in Education. (2014). +*Standards for educational and psychological testing*. American +Educational Research Association. + +GitHub, Inc. (n.d.-a). *Events that trigger workflows*. GitHub Docs. +Retrieved August 17, 2026, from +https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule + +GitHub, Inc. (n.d.-b). *Reuse workflows*. GitHub Docs. Retrieved August +17, 2026, from +https://docs.github.com/en/actions/how-tos/sharing-automations/reuse-workflows + +GitHub, Inc. (n.d.-c). *Automatic token authentication*. GitHub Docs. +Retrieved August 17, 2026, from +https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token + +MITRE. (2026). *CWE-250: Execution with unnecessary privileges*. +https://cwe.mitre.org/data/definitions/250.html + +National Institute of Standards and Technology. (2022). *Secure software +development framework (SSDF) version 1.1: Recommendations for mitigating +the risk of software vulnerabilities* (NIST Special Publication 800-218). +https://doi.org/10.6028/NIST.SP.800-218 + +NVIDIA. (n.d.). *NVIDIA NIM for large language models documentation*. +Retrieved August 17, 2026, from +https://docs.nvidia.com/nim/large-language-models/latest/ + +OpenCode. (n.d.). *OpenCode documentation*. Retrieved August 17, 2026, +from https://opencode.ai/docs/ diff --git a/tests/test_psychometrics_commons_hourly_review_caller.py b/tests/test_psychometrics_commons_hourly_review_caller.py new file mode 100644 index 000000000..74449c372 --- /dev/null +++ b/tests/test_psychometrics_commons_hourly_review_caller.py @@ -0,0 +1,178 @@ +"""Contract tests for psychometrics-commons' bounded hourly review-repair caller.""" + +from pathlib import Path + + +CALLER = Path(".github/workflows/psychometrics-commons-hourly-review-repair.yml") +DOCTORING = Path("docs/doctoring/psychometrics-commons-hourly-review-caller.md") +QUALITY_WORKFLOW = Path(".github/workflows/hourly-nvidia-nim-review-repair.yml") +SCHEDULER = Path(".github/workflows/pr-review-fix-scheduler.yml") + + +def _read(path: Path) -> str: + """Return one repository contract file as UTF-8 text.""" + return path.read_text(encoding="utf-8") + + +def _yaml_path_entries(block: str) -> set[str]: + """Return dashed YAML path entries from one trigger or compileall block.""" + entries: set[str] = set() + for raw_line in block.splitlines(): + stripped = raw_line.strip() + if stripped.startswith("- "): + entries.add(stripped[2:].strip()) + elif stripped.startswith("tests/") or stripped.startswith("scripts/"): + entries.add(stripped.rstrip(" \\")) + return entries + + +def _trigger_path_block(quality: str, trigger: str) -> str: + """Return the dashed path list under one named workflow trigger.""" + marker = f" {trigger}:\n paths:\n" + start = quality.index(marker) + len(marker) + lines: list[str] = [] + for line in quality[start:].splitlines(): + if line.startswith(" - "): + lines.append(line) + continue + if line.strip() == "": + continue + break + return "\n".join(lines) + + +def _compileall_block(quality: str) -> str: + """Return the compileall argument list from the focused quality job.""" + marker = "python -m compileall -q \\" + start = quality.index(marker) + remainder = quality[start:] + end = remainder.find("\n git ") + return remainder if end < 0 else remainder[:end] + + +def test_psychometrics_commons_caller_is_hourly_bounded_and_non_cancelling() -> None: + """psychometrics-commons receives one realistic repair without cancellation.""" + caller = _read(CALLER) + + assert 'cron: "9 * * * *"' in caller + assert "group: psychometrics-commons-hourly-review-repair" in caller + assert "cancel-in-progress: false" in caller + assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in caller + assert "target_repository: ContextualWisdomLab/psychometrics-commons" in caller + assert "base_branch: main" in caller + assert 'max_prs: "50"' in caller + assert 'max_dispatches: "1"' in caller + assert 'retry_hours: "2"' in caller + + +def test_psychometrics_commons_caller_preserves_oidc_and_explicit_secret_scope() -> None: + """The queue scanner maps established credentials without model secrets.""" + caller = _read(CALLER) + workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) + + assert "\npermissions:\n contents: read\n" in workflow_scope + assert ( + "\n permissions:\n contents: read\n id-token: write\n" + in jobs_scope + ) + assert "PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in caller + assert "OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}" in caller + assert "secrets: inherit" not in caller + assert "NVIDIA_NIM_API_KEY" not in caller + assert "COPILOT_GITHUB_TOKEN" not in caller + for forbidden in ( + "actions: write", + "contents: write", + "issues: write", + "pull-requests: write", + "statuses: write", + ): + assert forbidden not in caller + + +def test_psychometrics_commons_target_is_not_hard_coded_in_shared_scheduler() -> None: + """Product identity remains in the thin caller rather than the engine.""" + assert "ContextualWisdomLab/psychometrics-commons" not in _read(SCHEDULER) + + +def test_psychometrics_commons_doctoring_records_measurement_activation() -> None: + """Operators retain target-allowlist, measurement, and approval prerequisites.""" + doctoring = _read(DOCTORING) + + for phrase in ( + "ContextualWisdomLab/psychometrics-commons", + "OPENCODE_REPOSITORY_DISPATCH_TARGETS", + "independent non-author approval", + "NVIDIA_NIM_API_KEY", + "COPILOT_GITHUB_TOKEN", + "id-token: write", + "two-hour same-head retry floor", + "root-cause analysis", + "remediation feasibility", + "protected-main operational acceptance", + "APA 7th references", + "ContextualWisdomLab/psychometrics-commons#244", + "ContextualWisdomLab/psychometrics-commons#242", + "ContextualWisdomLab/psychometrics-commons#240", + "ContextualWisdomLab/psychometrics-commons#237", + "true-parameter recovery", + "operational-PII mask", + ): + assert phrase in doctoring + + +def test_path_block_helpers_keep_trigger_and_compileall_sets_disjoint() -> None: + """A path listed only under push or compileall must not satisfy pull_request.""" + quality = ( + "on:\n" + " pull_request:\n" + " paths:\n" + " - .github/workflows/psychometrics-commons-hourly-review-repair.yml\n" + " push:\n" + " paths:\n" + " - docs/doctoring/psychometrics-commons-hourly-review-caller.md\n" + " python -m compileall -q \\\n" + " tests/test_psychometrics_commons_hourly_review_caller.py\n" + " git diff --check\n" + ) + + pull_request_paths = _yaml_path_entries(_trigger_path_block(quality, "pull_request")) + push_paths = _yaml_path_entries(_trigger_path_block(quality, "push")) + compileall_paths = _yaml_path_entries(_compileall_block(quality)) + + assert pull_request_paths == { + ".github/workflows/psychometrics-commons-hourly-review-repair.yml" + } + assert push_paths == {"docs/doctoring/psychometrics-commons-hourly-review-caller.md"} + assert compileall_paths == { + "tests/test_psychometrics_commons_hourly_review_caller.py" + } + assert ( + "docs/doctoring/psychometrics-commons-hourly-review-caller.md" + not in pull_request_paths + ) + assert ( + ".github/workflows/psychometrics-commons-hourly-review-repair.yml" + not in compileall_paths + ) + + +def test_focused_quality_workflow_tracks_psychometrics_commons_contracts() -> None: + """Caller, test, and doctoring edits always rerun the focused gate.""" + quality = _read(QUALITY_WORKFLOW) + pull_request_paths = _yaml_path_entries(_trigger_path_block(quality, "pull_request")) + push_paths = _yaml_path_entries(_trigger_path_block(quality, "push")) + compileall_paths = _yaml_path_entries(_compileall_block(quality)) + caller = ".github/workflows/psychometrics-commons-hourly-review-repair.yml" + doctoring = "docs/doctoring/psychometrics-commons-hourly-review-caller.md" + contract = "tests/test_psychometrics_commons_hourly_review_caller.py" + + assert caller in pull_request_paths + assert doctoring in pull_request_paths + assert contract in pull_request_paths + assert caller in push_paths + assert doctoring in push_paths + assert contract in push_paths + assert contract in compileall_paths + assert caller not in compileall_paths + assert doctoring not in compileall_paths From 766b92d9af6deb7cc1c81616e4ed15abc3d22c6d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 12:24:49 -0700 Subject: [PATCH 2/2] fix(changelog): keep caller entries categorized --- CHANGELOG.md | 9 +-------- ...chometrics_commons_hourly_review_caller.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b86b8733..727e8a16f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Semantic Versioning where the repository publishes a release. - Run the bounded Clearfolio PR review-feedback repair caller at minute 23 of every hour while keeping the shared scheduler free of product-specific timers and repository names for modular reuse by naruon, contextual-orchestrator, Inkspan, and other CWL services. - Run the bounded DiskSage repair heartbeat at minute 37 of every hour, dispatch no more than one exact-head repair, and wait two hours before redispatching an unchanged head so legitimate OpenCode or NVIDIA NIM latency does not create duplicate writers. - Run the bounded fast-mlsirm repair heartbeat at minute 49 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening true-parameter recovery, CPU/GPU parity, skipped-test, or Rust-ownership gates. +- Run the bounded psychometrics-commons repair heartbeat at minute 9 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening measurement-governance, consent-ledger, or scientific-recovery gates. - Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603` with explicit high reasoning for scheduled repair and `nvidia/nemotron-3-nano-30b-a3b` for bounded helper work instead of GitHub Models in the write-capable autofix worker. - Apply one NUL-delimited exact-path and complete pre/post-worktree verification contract to both ordinary review repair and merge-conflict repair rather than relying on a visible post-model diff for the ordinary path. @@ -40,12 +41,6 @@ Semantic Versioning where the repository publishes a release. - Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109). - Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109). - Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories. -- Run the bounded psychometrics-commons repair heartbeat at minute 9 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening measurement-governance, consent-ledger, or scientific-recovery gates. -- Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603` with explicit high reasoning for scheduled repair and `nvidia/nemotron-3-nano-30b-a3b` for bounded helper work instead of GitHub Models in the write-capable autofix worker. -- Apply one NUL-delimited exact-path and complete pre/post-worktree verification contract to both ordinary review repair and merge-conflict repair rather than relying on a visible post-model diff for the ordinary path. - -### Fixed - - Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context. - Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367). - Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. @@ -87,5 +82,3 @@ Semantic Versioning where the repository publishes a release. - Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. - Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. - Added psychometrics-commons operational documentation for the hourly RCA loop, measurement and consent gates, bounded retry cadence, credential isolation, modular reuse, rollback, and APA 7 references. -- Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. -- Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. \ No newline at end of file diff --git a/tests/test_psychometrics_commons_hourly_review_caller.py b/tests/test_psychometrics_commons_hourly_review_caller.py index 74449c372..9899f87ed 100644 --- a/tests/test_psychometrics_commons_hourly_review_caller.py +++ b/tests/test_psychometrics_commons_hourly_review_caller.py @@ -4,6 +4,7 @@ CALLER = Path(".github/workflows/psychometrics-commons-hourly-review-repair.yml") +CHANGELOG = Path("CHANGELOG.md") DOCTORING = Path("docs/doctoring/psychometrics-commons-hourly-review-caller.md") QUALITY_WORKFLOW = Path(".github/workflows/hourly-nvidia-nim-review-repair.yml") SCHEDULER = Path(".github/workflows/pr-review-fix-scheduler.yml") @@ -95,6 +96,24 @@ def test_psychometrics_commons_target_is_not_hard_coded_in_shared_scheduler() -> assert "ContextualWisdomLab/psychometrics-commons" not in _read(SCHEDULER) +def test_changelog_keeps_psychometrics_entry_categorized_and_unique() -> None: + """The caller entry belongs in Changed without duplicating shared notes.""" + unreleased = _read(CHANGELOG).split("## [Unreleased]\n", maxsplit=1)[1] + changed = unreleased.split("### Changed\n", maxsplit=1)[1].split("\n### ", maxsplit=1)[0] + heartbeat = ( + "Run the bounded psychometrics-commons repair heartbeat at minute 9 of every hour " + "with one-dispatch scope and a two-hour same-head floor" + ) + + assert heartbeat in changed + assert unreleased.count(heartbeat) == 1 + assert unreleased.count("### Fixed\n") == 1 + assert unreleased.count("Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603`") == 1 + assert unreleased.count("Apply one NUL-delimited exact-path") == 1 + assert unreleased.count("Documented the ordinary and conflict repair write-scope parity") == 1 + assert unreleased.count("Documented the review-authentication boundary") == 1 + + def test_psychometrics_commons_doctoring_records_measurement_activation() -> None: """Operators retain target-allowlist, measurement, and approval prerequisites.""" doctoring = _read(DOCTORING)