From 9708abde9b3c519cccac1e138dc10ad86a25e245 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 22 Aug 2026 19:46:48 +0200 Subject: [PATCH 1/4] ci: enable GitHub CodeQL code scanning GET /repos/unbraind/pm-github/code-scanning/alerts returned HTTP 404 "no analysis found" on 2026-08-22: code scanning has never produced an analysis here, so the Security tab could not distinguish "clean" from "never ran". Add .github/workflows/codeql.yml: - languages: javascript-typescript, build-mode: none - triggers: push to main, pull_request to main, weekly staggered schedule - permissions limited to security-events:write, actions:read, contents:read - github/codeql-action pinned at v4 (fleet major-tag convention) Deliberately advisory, not a required status check: a brand-new required check that has never reported would block every PR in this repo. Tracked as pm-github-sx18. --- .agents/pm/chores/pm-github-sx18.toon | 23 ++++++++++++++++ .agents/pm/history/pm-github-sx18.jsonl | 6 +++++ .github/workflows/codeql.yml | 35 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 .agents/pm/chores/pm-github-sx18.toon create mode 100644 .agents/pm/history/pm-github-sx18.jsonl create mode 100644 .github/workflows/codeql.yml diff --git a/.agents/pm/chores/pm-github-sx18.toon b/.agents/pm/chores/pm-github-sx18.toon new file mode 100644 index 0000000..f0109c3 --- /dev/null +++ b/.agents/pm/chores/pm-github-sx18.toon @@ -0,0 +1,23 @@ +id: pm-github-sx18 +title: Enable GitHub CodeQL code scanning +description: "Add .github/workflows/codeql.yml (javascript-typescript, build-mode none, weekly staggered schedule). GET code-scanning/alerts returned 404 no-analysis-found, so the Security tab could not distinguish clean from never-ran. Advisory check only, not added to branch protection." +type: Chore +status: in_progress +priority: 2 +tags: [] +created_at: "2026-08-22T17:43:42.366Z" +updated_at: "2026-08-22T17:43:55.186Z" +author: "harness:ox-alpha" +notes[1]{created_at,author,text}: + "2026-08-22T17:43:54.385Z","harness:ox-alpha","Verified 2026-08-22: gh api repos/unbraind/pm-github/code-scanning/alerts -> 404 'no analysis found'. Workflow pins github/codeql-action v4 (fleet major-tag convention), permissions limited to security-events:write/actions:read/contents:read." +files[1]{path,scope,note}: + .github/workflows/codeql.yml,project,CodeQL scanning workflow - javascript-typescript build-mode none weekly staggered cron +tests[2]: + - command: gh run list -R unbraind/pm-github --branch ci/enable-codeql-scanning + scope: project + note: CodeQL workflow run succeeds on the PR branch + - command: gh api repos/unbraind/pm-github/code-scanning/alerts + scope: project + assert_stdout_regex[1]: rule_id|most_recent_instance|analysis_key + note: code-scanning alerts endpoint returns an analysis instead of 404 no-analysis-found +body: "" diff --git a/.agents/pm/history/pm-github-sx18.jsonl b/.agents/pm/history/pm-github-sx18.jsonl new file mode 100644 index 0000000..eac3415 --- /dev/null +++ b/.agents/pm/history/pm-github-sx18.jsonl @@ -0,0 +1,6 @@ +{"ts":"2026-08-22T17:43:42.366Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-sx18"},{"op":"add","path":"/metadata/title","value":"Enable GitHub CodeQL code scanning"},{"op":"add","path":"/metadata/description","value":"Add .github/workflows/codeql.yml (javascript-typescript, build-mode none, weekly staggered schedule). GET code-scanning/alerts returned 404 no-analysis-found, so the Security tab could not distinguish clean from never-ran. Advisory check only, not added to branch protection."},{"op":"add","path":"/metadata/type","value":"Chore"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-08-22T17:43:42.366Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-22T17:43:42.366Z"},{"op":"add","path":"/metadata/author","value":"harness:ox-alpha"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"f21c68bd3ac2d5ddb85375c3f69f92ec1f33e402340904c6800129bc95717f89","item_hash_version":2,"message":""} +{"ts":"2026-08-22T17:43:53.564Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:53.564Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"f21c68bd3ac2d5ddb85375c3f69f92ec1f33e402340904c6800129bc95717f89","after_hash":"41f5916e9f28a6ba329ddbd47f69197552b429ea82392ad03fc72b1f34864493","item_hash_version":2} +{"ts":"2026-08-22T17:43:53.976Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:53.976Z"},{"op":"add","path":"/metadata/files","value":[{"path":".github/workflows/codeql.yml","scope":"project","note":"CodeQL scanning workflow - javascript-typescript build-mode none weekly staggered cron"}]}],"before_hash":"41f5916e9f28a6ba329ddbd47f69197552b429ea82392ad03fc72b1f34864493","after_hash":"6d39c1edacca1c493748e73983049370ebec15528114637e2218f59a90bf07ea","item_hash_version":2} +{"ts":"2026-08-22T17:43:54.386Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:54.386Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-22T17:43:54.385Z","author":"harness:ox-alpha","text":"Verified 2026-08-22: gh api repos/unbraind/pm-github/code-scanning/alerts -> 404 'no analysis found'. Workflow pins github/codeql-action v4 (fleet major-tag convention), permissions limited to security-events:write/actions:read/contents:read."}]}],"before_hash":"6d39c1edacca1c493748e73983049370ebec15528114637e2218f59a90bf07ea","after_hash":"163a8bedd573e0a27b228d5531cf777b316a703cdd88de7ff527d28433d29a3e","item_hash_version":2} +{"ts":"2026-08-22T17:43:54.780Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:54.780Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"gh run list -R unbraind/pm-github --branch ci/enable-codeql-scanning","scope":"project","note":"CodeQL workflow run succeeds on the PR branch"}]}],"before_hash":"163a8bedd573e0a27b228d5531cf777b316a703cdd88de7ff527d28433d29a3e","after_hash":"eba66200d904b6205fea2eb071a6291d09dd0f2c94ad96a3c2f7852258ee6c49","item_hash_version":2} +{"ts":"2026-08-22T17:43:55.186Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"gh api repos/unbraind/pm-github/code-scanning/alerts","scope":"project","assert_stdout_regex":["rule_id|most_recent_instance|analysis_key"],"note":"code-scanning alerts endpoint returns an analysis instead of 404 no-analysis-found"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:55.186Z"}],"before_hash":"eba66200d904b6205fea2eb071a6291d09dd0f2c94ad96a3c2f7852258ee6c49","after_hash":"3a1a33f00425b625041a885994decf27bd12c8e5fd96a769cb7aeb8784e79bde","item_hash_version":2} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f037c63 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,35 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + # Weekly CodeQL scan, minute/hour staggered across the pm fleet so the + # repos do not all fire against the API at the same time. + - cron: "43 3 * * 1" + +permissions: + security-events: write + actions: read + contents: read + +jobs: + codeql: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: javascript-typescript + # These packages are analyzed from source without a compiled build. + build-mode: none + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:javascript-typescript" From 7b47dca984f571c0f8dc7c5ff849596f68c4a824 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 22 Aug 2026 19:53:04 +0200 Subject: [PATCH 2/4] ci(codeql): pin actions by digest and stop duplicate scans of one ref Applies three review findings across every CodeQL workflow in the fleet in one sweep, rather than one PR at a time. Greptile flagged mutable action references. I checked whether the fleet had a convention to defer to before accepting that, because deferring would have been the better answer if one existed. It does not: the fleet is split, 113 SHA-pinned references against 129 tag references. With nothing to defer to, digest pinning is the right call for a security-scanning workflow in particular, since a moved tag would silently change what scans the code. actions/checkout@v7 and github/codeql-action@v4 are pinned to the digests those tags currently resolve to, with the tag retained in a trailing comment; the checkout digest is the one already used elsewhere in the fleet. CodeRabbit flagged that repeated pushes run concurrent scans of the same ref. A concurrency group now cancels superseded runs, but only for pull_request events: cancelling a push or a scheduled run would leave the default branch without a fresh analysis, which is the condition this whole workflow exists to remove. --- .github/workflows/codeql.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f037c63..304e820 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,6 +10,10 @@ on: # repos do not all fire against the API at the same time. - cron: "43 3 * * 1" +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: security-events: write actions: read @@ -20,16 +24,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 with: languages: javascript-typescript # These packages are analyzed from source without a compiled build. build-mode: none - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 with: category: "/language:javascript-typescript" From 93c89d8a51d6433eb532492a2e070dee9e7f0f15 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 22 Aug 2026 19:54:52 +0200 Subject: [PATCH 3/4] ci(codeql): scope permissions to the job and stop persisting the checkout token Two further review findings, applied across every CodeQL workflow. Permissions were granted at workflow level, which is strictly wider than this workflow needs and would silently extend to any job added later. They now sit on the single codeql job that actually uses them. actions/checkout leaves the job token in .git/config by default. Nothing in this workflow pushes, so persist-credentials: false removes a credential that would otherwise be readable by any later step - which matters more here than usual, since the whole point of the workflow is to analyse code that may be attacker-influenced on a pull_request trigger. Both changes are asserted structurally rather than by eye: the check parses the YAML and requires top-level permissions to be absent, the job permissions to equal the exact three-key grant, persist-credentials to be literally false, and the codeql-action reference to carry the pinned digest. An earlier version of this sweep emitted the permissions block at the wrong indentation, which a weaker check that only tested for the key would have passed. --- .github/workflows/codeql.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 304e820..818231d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,17 +14,18 @@ concurrency: group: codeql-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} -permissions: - security-events: write - actions: read - contents: read - jobs: codeql: + permissions: + security-events: write + actions: read + contents: read runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - name: Initialize CodeQL uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 From 5bf17f5b9d02b497bb80c72fb44b6b5f3013d647 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 22 Aug 2026 20:00:52 +0200 Subject: [PATCH 4/4] test(codeql): make the recorded acceptance tests fail closed Seven review threads across these PRs said the same thing in different words: the recorded validation tests do not assert anything, so they pass whether or not CodeQL works. They were right, and this is the more serious finding in the batch, because an acceptance record that cannot fail is worse than no record - it reads as evidence. Both entries are replaced in every CodeQL tracking item. The workflow check asserted nothing at all. `gh run list` prints a failed run just as happily as a successful one, so the entry passed while the scan was broken. It now requests `--json conclusion` and asserts `^success$`. The alerts check queried `/code-scanning/alerts` with a regex matching only non-empty alert objects. That is wrong twice over: an empty array is the correct answer for a clean repository, so the assertion failed on success, and an empty array is in any case ambiguous between analysed-and-clean and never-analysed - which is precisely the ambiguity these PRs exist to remove. The entry now queries `/code-scanning/analyses` and asserts at least one CodeQL analysis exists, which answers did-a-scan-run directly. Verified in both directions rather than assumed. All seven repositories run green (`assertion_failure: 0`), which also confirms each now has a real analysis. Against a repository with no CodeQL yet, `/analyses` returns HTTP 404 `no analysis found` and gh exits non-zero, so the assertion fails closed. One note on process: the first version of the analyses command stored the jq filter unquoted, and the shell consumed the pipe. Running the tests caught it; reading them would not have. --- .agents/pm/chores/pm-github-sx18.toon | 13 +++++++------ .agents/pm/history/pm-github-sx18.jsonl | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.agents/pm/chores/pm-github-sx18.toon b/.agents/pm/chores/pm-github-sx18.toon index f0109c3..0495ad0 100644 --- a/.agents/pm/chores/pm-github-sx18.toon +++ b/.agents/pm/chores/pm-github-sx18.toon @@ -6,18 +6,19 @@ status: in_progress priority: 2 tags: [] created_at: "2026-08-22T17:43:42.366Z" -updated_at: "2026-08-22T17:43:55.186Z" +updated_at: "2026-08-22T18:00:00.764Z" author: "harness:ox-alpha" notes[1]{created_at,author,text}: "2026-08-22T17:43:54.385Z","harness:ox-alpha","Verified 2026-08-22: gh api repos/unbraind/pm-github/code-scanning/alerts -> 404 'no analysis found'. Workflow pins github/codeql-action v4 (fleet major-tag convention), permissions limited to security-events:write/actions:read/contents:read." files[1]{path,scope,note}: .github/workflows/codeql.yml,project,CodeQL scanning workflow - javascript-typescript build-mode none weekly staggered cron tests[2]: - - command: gh run list -R unbraind/pm-github --branch ci/enable-codeql-scanning + - command: "gh run list -R unbraind/pm-github --workflow codeql.yml --branch ci/enable-codeql-scanning --limit 1 --json conclusion --jq '.[0].conclusion'" scope: project - note: CodeQL workflow run succeeds on the PR branch - - command: gh api repos/unbraind/pm-github/code-scanning/alerts + assert_stdout_regex[1]: ^success$ + note: "The CodeQL workflow must have a COMPLETED SUCCESSFUL run on this branch. Asserting the conclusion rather than the presence of a run: gh run list prints a failed run too, so an unasserted invocation passes while the scan is broken." + - command: "gh api repos/unbraind/pm-github/code-scanning/analyses --jq '[.[]|select(.tool.name==\"CodeQL\")]|length'" scope: project - assert_stdout_regex[1]: rule_id|most_recent_instance|analysis_key - note: code-scanning alerts endpoint returns an analysis instead of 404 no-analysis-found + assert_stdout_regex[1]: "^[1-9][0-9]*$" + note: "At least one CodeQL analysis must exist. Deliberately queries /analyses, not /alerts: an empty /alerts array is ambiguous between analysed-and-clean and never-analysed, and that ambiguity is the exact defect this change removes. /analyses answers did-a-scan-run directly, so a clean repo passes and an unscanned one fails closed with HTTP 404." body: "" diff --git a/.agents/pm/history/pm-github-sx18.jsonl b/.agents/pm/history/pm-github-sx18.jsonl index eac3415..a045b74 100644 --- a/.agents/pm/history/pm-github-sx18.jsonl +++ b/.agents/pm/history/pm-github-sx18.jsonl @@ -4,3 +4,6 @@ {"ts":"2026-08-22T17:43:54.386Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:54.386Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-22T17:43:54.385Z","author":"harness:ox-alpha","text":"Verified 2026-08-22: gh api repos/unbraind/pm-github/code-scanning/alerts -> 404 'no analysis found'. Workflow pins github/codeql-action v4 (fleet major-tag convention), permissions limited to security-events:write/actions:read/contents:read."}]}],"before_hash":"6d39c1edacca1c493748e73983049370ebec15528114637e2218f59a90bf07ea","after_hash":"163a8bedd573e0a27b228d5531cf777b316a703cdd88de7ff527d28433d29a3e","item_hash_version":2} {"ts":"2026-08-22T17:43:54.780Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:54.780Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"gh run list -R unbraind/pm-github --branch ci/enable-codeql-scanning","scope":"project","note":"CodeQL workflow run succeeds on the PR branch"}]}],"before_hash":"163a8bedd573e0a27b228d5531cf777b316a703cdd88de7ff527d28433d29a3e","after_hash":"eba66200d904b6205fea2eb071a6291d09dd0f2c94ad96a3c2f7852258ee6c49","item_hash_version":2} {"ts":"2026-08-22T17:43:55.186Z","author":"harness:ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"73ffe9cf6d87e6e059050f65","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"gh api repos/unbraind/pm-github/code-scanning/alerts","scope":"project","assert_stdout_regex":["rule_id|most_recent_instance|analysis_key"],"note":"code-scanning alerts endpoint returns an analysis instead of 404 no-analysis-found"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:43:55.186Z"}],"before_hash":"eba66200d904b6205fea2eb071a6291d09dd0f2c94ad96a3c2f7852258ee6c49","after_hash":"3a1a33f00425b625041a885994decf27bd12c8e5fd96a769cb7aeb8784e79bde","item_hash_version":2} +{"ts":"2026-08-22T17:59:59.257Z","author":"codex","author_source":"configured","agent_harness":"claude-code","agent_instance":"d8080bf24e1b0babea915d0e","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":null},"op":"tests_remove","patch":[{"op":"remove","path":"/metadata/tests/1"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:59:59.257Z"}],"before_hash":"3a1a33f00425b625041a885994decf27bd12c8e5fd96a769cb7aeb8784e79bde","after_hash":"3575b4516e8eeef428ee7a2c8512060022d374c2cb4d7ab0448af688d04a99db","item_hash_version":2,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"}}}} +{"ts":"2026-08-22T17:59:59.729Z","author":"codex","author_source":"configured","agent_harness":"claude-code","agent_instance":"d8080bf24e1b0babea915d0e","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":null},"op":"tests_remove","patch":[{"op":"remove","path":"/metadata/tests"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T17:59:59.729Z"}],"before_hash":"3575b4516e8eeef428ee7a2c8512060022d374c2cb4d7ab0448af688d04a99db","after_hash":"0e8165f05850957c22602f68fa824c007c6a29e3bdd8bffcde633c1735977610","item_hash_version":2,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"}}}} +{"ts":"2026-08-22T18:00:00.764Z","author":"codex","author_source":"configured","agent_harness":"claude-code","agent_instance":"d8080bf24e1b0babea915d0e","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-22T18:00:00.764Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"gh run list -R unbraind/pm-github --workflow codeql.yml --branch ci/enable-codeql-scanning --limit 1 --json conclusion --jq '.[0].conclusion'","scope":"project","assert_stdout_regex":["^success$"],"note":"The CodeQL workflow must have a COMPLETED SUCCESSFUL run on this branch. Asserting the conclusion rather than the presence of a run: gh run list prints a failed run too, so an unasserted invocation passes while the scan is broken."},{"command":"gh api repos/unbraind/pm-github/code-scanning/analyses --jq '[.[]|select(.tool.name==\"CodeQL\")]|length'","scope":"project","assert_stdout_regex":["^[1-9][0-9]*$"],"note":"At least one CodeQL analysis must exist. Deliberately queries /analyses, not /alerts: an empty /alerts array is ambiguous between analysed-and-clean and never-analysed, and that ambiguity is the exact defect this change removes. /analyses answers did-a-scan-run directly, so a clean repo passes and an unscanned one fails closed with HTTP 404."}]}],"before_hash":"0e8165f05850957c22602f68fa824c007c6a29e3bdd8bffcde633c1735977610","after_hash":"87a80952db0eb89c38cd8c0d69c35d100652a13f33de8c3ff62119ce1ae03793","item_hash_version":2,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"failed","reason":"resolver_failed","resolver":"claude_session_file","rule_version":"v1"}}}}