Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 125 additions & 1 deletion .github/workflows/ci-extended.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,136 @@ jobs:
workflow-lint:
name: Workflow Lint
runs-on: ubuntu-latest
timeout-minutes: 10
env:
ACTIONLINT_VERSION: "1.7.12"
ACTIONLINT_ARCHIVE_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
PYFLAKES_VERSION: "3.4.0"
PYFLAKES_WHEEL_SHA256: f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false

- name: Install Actionlint toolchain
shell: bash
run: |
set -euo pipefail

archive_name="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
Comment thread
Chris0Jeky marked this conversation as resolved.
archive_path="${RUNNER_TEMP}/${archive_name}"
install_dir="${RUNNER_TEMP}/actionlint-${ACTIONLINT_VERSION}"
download_url="https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/${archive_name}"

curl \
--fail \
--silent \
--show-error \
--location \
--proto '=https' \
--tlsv1.2 \
--connect-timeout 15 \
--max-time 120 \
--retry 3 \
--retry-all-errors \
--retry-max-time 240 \
--output "${archive_path}" \
"${download_url}"
bash scripts/ci/verify-sha256.sh "${ACTIONLINT_ARCHIVE_SHA256}" "${archive_path}"

mkdir -p "${install_dir}"
tar --extract --gzip --file "${archive_path}" --directory "${install_dir}" actionlint
actionlint_bin="${install_dir}/actionlint"
if [ ! -f "${actionlint_bin}" ] || [ -L "${actionlint_bin}" ]; then
echo "::error::Extracted Actionlint must be a regular file and not a symbolic link"
exit 1
fi
chmod 0755 "${actionlint_bin}"

version_output="$("${actionlint_bin}" -version)"
actual_version="${version_output%%$'\n'*}"
if [ "${actual_version}" != "${ACTIONLINT_VERSION}" ]; then
echo "::error::Expected Actionlint ${ACTIONLINT_VERSION}, got ${actual_version}"
exit 1
fi
printf '%s\n' "${version_output}"

pyflakes_wheel_name="pyflakes-${PYFLAKES_VERSION}-py2.py3-none-any.whl"
pyflakes_wheel_path="${RUNNER_TEMP}/${pyflakes_wheel_name}"
pyflakes_download_url="https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/${pyflakes_wheel_name}"
pyflakes_venv="${RUNNER_TEMP}/pyflakes-${PYFLAKES_VERSION}"

curl \
--fail \
--silent \
--show-error \
--location \
--proto '=https' \
--tlsv1.2 \
--connect-timeout 15 \
--max-time 120 \
--retry 3 \
--retry-all-errors \
--retry-max-time 240 \
--output "${pyflakes_wheel_path}" \
"${pyflakes_download_url}"
bash scripts/ci/verify-sha256.sh "${PYFLAKES_WHEEL_SHA256}" "${pyflakes_wheel_path}"

python3 -m venv "${pyflakes_venv}"
"${pyflakes_venv}/bin/python" -m pip install \
--disable-pip-version-check \
--no-deps \
--no-index \
"${pyflakes_wheel_path}"
pyflakes_bin="${pyflakes_venv}/bin/pyflakes"
if [ ! -f "${pyflakes_bin}" ] || [ -L "${pyflakes_bin}" ] || [ ! -x "${pyflakes_bin}" ]; then
echo "::error::Installed Pyflakes entry point is not a regular executable file"
exit 1
fi
pyflakes_version_output="$("${pyflakes_bin}" --version)"
pyflakes_version="${pyflakes_version_output%% *}"
if [ "${pyflakes_version}" != "${PYFLAKES_VERSION}" ]; then
echo "::error::Expected Pyflakes ${PYFLAKES_VERSION}, got ${pyflakes_version}"
exit 1
fi
printf '%s\n' "${pyflakes_version_output}"

if ! shellcheck_bin="$(command -v shellcheck)"; then
echo "::error::ShellCheck is missing or not executable"
exit 1
fi
if [ ! -x "${shellcheck_bin}" ]; then
echo "::error::ShellCheck is missing or not executable"
exit 1
fi
"${shellcheck_bin}" --version

{
printf 'ACTIONLINT_BIN=%s\n' "${actionlint_bin}"
printf 'ACTIONLINT_SHELLCHECK_BIN=%s\n' "${shellcheck_bin}"
printf 'ACTIONLINT_PYFLAKES_BIN=%s\n' "${pyflakes_bin}"
} >> "${GITHUB_ENV}"

- name: Test Actionlint bootstrap contract
run: node --test scripts/ci/actionlint-bootstrap.test.mjs

- name: Run actionlint
uses: rhysd/actionlint@v1.7.12
shell: bash
run: |
set -euo pipefail
checkout_head="$(git rev-parse --verify HEAD)"
workflow_count="$(find .github/workflows -maxdepth 1 -type f \( -name '*.yml' -o -name '*.yaml' \) -print | awk 'END { print NR }')"
if [ "${workflow_count}" -le 0 ]; then
echo "::error::No workflow files found after checkout"
exit 1
fi
printf 'Checked out HEAD: %s\nWorkflow files discovered: %s\n' "${checkout_head}" "${workflow_count}"
"${ACTIONLINT_BIN}" \
-color \
-verbose \
-shellcheck "${ACTIONLINT_SHELLCHECK_BIN}" \
-pyflakes "${ACTIONLINT_PYFLAKES_BIN}"

dependency-review:
name: Dependency Review
Expand Down
4 changes: 4 additions & 0 deletions docs/IMPLEMENTATION_MASTERPLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Companion Active Docs:
- **Post-`#1373` diagnostic successor (`#1512`):** structured, bounded correlation plus outer/last-inspected exception type, explicit truncation, aggregate-branch, and SQLite-code evidence is now available when the concurrent-card assertion fails. Normal middleware logs are metadata-only, the client still receives the generic GP-03 500, and no request/user/credential/exception-message content enters the diagnostic sink. Pre/post exact stress, the five-case historical/current concurrency matrix, and five CI-equivalent API runs stayed green and did not reproduce the original 500; therefore no causal exception, `SQLITE_BUSY` classification, retry, quarantine, or product fix is claimed.
- **Still open:** retain `#1512` until a real recurrence identifies the cause and the narrow repair passes the full serialized backend suite plus exact-head Windows/Ubuntu CI.

## Staged runway repair (2026-07-27, maintainer-held)

- **Workflow Lint bootstrap (`#1510`):** replace the Docker Actionlint action, whose pre-checkout Docker Hub manifest fetch timed out in two exact-code CI Extended runs, with a fail-closed direct bootstrap. Pin and checksum Actionlint 1.7.12 plus the Pyflakes 3.4.0 wheel, retain runner ShellCheck through an explicit path, install Pyflakes offline, bound downloads and the job, and log the exact checkout/tool/workflow inventory before verbose linting. Seven focused contract checks and two independent design reviews are complete locally. Exact-head-associated hosted Ubuntu proof is green with both checksums, 7/7 contract checks, and zero errors across 32 workflows without a Docker build. The workflow change remains T4-class and unshipped until maintainer merge plus fresh post-merge proof.

## Delivery update (2026-07-26, agentic governance)

- **Failure-ledger projection gate (`#1492`):** Required Docs Governance now pins Python 3.12 and runs the existing JSONL↔Markdown synchronization unittest before the governance checks, so a JSONL-only change with stale generated Markdown fails Required CI without regeneration masking it. Local agentic update workflows use the distinct render-then-test order so hook-appended JSONL can be projected, and the smoke contract pins both sides of that distinction.
Expand Down
3 changes: 3 additions & 0 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Windows concurrent-card HTTP-500 diagnostics (2026-07-27, `#1512`; diagnostic-on
- **A same-symptom failure recurred after `#1373`, but did not reproduce locally.** Required `API Integration (windows-latest)` on PR `#1505` at source head `6ee17a4849427d679722a9d1e034d4622536f4fe` returned HTTP 500 for 2/5 simultaneous card creates; Ubuntu and one identical-head rerun passed. Pre-change local proof was 20/20 exact runs plus one full API run at 2,128 passed / 4 skipped / 0 failed. Post-diagnostic proof includes focused diagnostics 6/6, the final exact race 20/20, a five-case historical/current concurrency matrix 5/5, and five CI-equivalent full API runs: three at 2,129/4/0 before the final formatter regression and two at 2,130/4/0 after it. The review-fix head then passed its 13/13 focused regressions and a 2,132-passed / 4-skipped / 0-failed full API run. No run captured a spontaneous 500, causal exception, or SQLite classification.
- **The new seam improves the next failure's evidence without masking it.** Unhandled middleware emits bounded structured outer/last-inspected exception types, an explicit classification-truncated flag, and SQLite primary/extended codes beside the bounded correlation identity while retaining the generic GP-03 500 response. The bounded graph walk inspects aggregate branches without calling the last inspected wrapper a root. Normal middleware logs are metadata-only; the test harness captures only structured fields. A failed race assertion joins request/response correlation, status/error code, and matching middleware classification into a sanitized 2,048-character diagnostic. It records no request/response body, credential, user content, exception message, exception summary, or exception object. The injected SQLite 5/5 contract proves the diagnostic transport only; it does not classify the original failure as `SQLITE_BUSY`. No retry, quarantine, or product fix was added, and `#1512` remains open.

Workflow-lint runway repair staged (2026-07-27, `#1510`):
- **The maintainer-held workflow candidate removes Actionlint's Docker Hub build from CI Extended without weakening its external-linter contract.** It downloads the pinned Actionlint 1.7.12 Linux archive and Pyflakes 3.4.0 wheel over bounded HTTPS, verifies both published SHA-256 digests before use, installs Pyflakes offline, and passes explicit ShellCheck and Pyflakes paths to Actionlint. The job also logs tool versions, the checked-out head, and the discovered workflow count, and runs a seven-check bootstrap contract before the repository lint. Local focused proof, two independent reviews, and exact-head-associated hosted Ubuntu proof are green: both checksums passed, the contract ran 7/7, and verbose Actionlint found zero errors in 32 workflows without a Docker build. This is not shipped reality yet: maintainer merge and fresh post-merge proof remain required, and runner-provided ShellCheck remains version-drift residual risk.

Required Docs Governance hardening (2026-07-26, `#1492`):
- **Required CI now enforces failure-ledger projection synchronization.** The reusable Docs Governance job pins Python 3.12 and runs the existing `failure_ledger.jsonl` ↔ `FAILURE_LEDGER.md` synchronization unittest before its governance checks, so a stale checked-in projection fails without any renderer masking it. Local agentic update workflows intentionally render first and then test so a valid hook-appended JSONL entry can be projected; the smoke contract keeps that distinction from drifting.

Expand Down
23 changes: 23 additions & 0 deletions docs/TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ Pop-Location
if ($code -ne 0) { exit $code }
```

## Workflow Lint Bootstrap Checks

CI Extended's `Workflow Lint` job bootstraps checksum-pinned Actionlint and Pyflakes artifacts directly, uses the Ubuntu runner's ShellCheck through an explicit path, runs the focused contract suite, then lints every checked-out workflow verbosely. The hosted job is the authoritative integration proof: its unchanged-head log must show both checksum checks, Actionlint 1.7.12, Pyflakes 3.4.0, the runner ShellCheck version, the checked-out SHA, a positive workflow count, seven passing contract checks, and a zero-error repository lint. A run that fails before checkout or never reads the workflows is not green evidence.

On native Windows, set Git Bash explicitly because bare `bash` can resolve to the Microsoft Store/WSL alias. The static, ordering, and checksum boundary is the portable fast path:

```powershell
$env:BASH_BIN = 'C:\Program Files\Git\bin\bash.exe'
node --test --test-name-pattern='pins|bootstrap boundary|checksum verifier' scripts/ci/actionlint-bootstrap.test.mjs
```

The full seven-check suite additionally requires local Actionlint, ShellCheck, and Pyflakes executables:

```powershell
$env:BASH_BIN = 'C:\Program Files\Git\bin\bash.exe'
$env:ACTIONLINT_BIN = '<path-to-actionlint>'
$env:ACTIONLINT_SHELLCHECK_BIN = '<path-to-shellcheck>'
$env:ACTIONLINT_PYFLAKES_BIN = '<path-to-pyflakes>'
node --test scripts/ci/actionlint-bootstrap.test.mjs
```

Do not infer external-linter coverage from Actionlint alone: Actionlint can skip ShellCheck or Pyflakes when they are unavailable. Keep the explicit tool paths and the fixture assertions for `SC2086` and the Pyflakes undefined-name diagnostic.

## Agentic Operating Layer Smoke Checks

For docs/skill/hook-only agentic changes, use targeted checks rather than the full product suite unless product runtime files changed. These local update-and-verify sequences render the failure ledger before testing synchronization so a valid hook-appended JSONL entry can become visible. Required CI deliberately does not render and keeps its test-before-governance order, so an unprojected JSONL change fails instead of being masked. On Windows PowerShell, use the verified Python launcher and compile hook sources in memory so verification does not leave `__pycache__` output:
Expand Down
1 change: 1 addition & 0 deletions docs/agentic/FAILURE_LEDGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Rows sharing a surface and first tracking issue in `future_fix` show only their
| 2026-07-26 | non_blocking_risk | agent/tool-command-composition | Resolution record for the repeated #1490 PowerShell/native command-composition failures; the original recurrence remains in append-only history | No workaround remains; use the copyable safe forms and classify future failures through the ledger process | #1490 resolved by PR #1491 merge 61f718af941c56c31b8b7595333b9debd6e47da8: the MCP tooling guide now covers collected foreach output, optional rg exits, safe mu... | resolved |
| 2026-07-26 | blocker | agent/python-launcher | Resolution staged for #1487: exact Windows handlers and agent-utility permissions use py -3 -B, POSIX permissions retain python3 -B, and smoke children use the ... | Until the T4-class hook configuration is maintainer-merged, continue invoking py -3 -B explicitly on native Windows | #1487 resolution is staged on the human-held PR with sequential CPython 3.14 and 3.13 smoke coverage; append the final resolved record after merge and issue clo... | open |
| 2026-07-26 | blocker | agent/powershell-deny-floor | The repo PreToolUse deny policy is matched only to Bash, so native PowerShell tool commands do not traverse the repository's destructive-command policy | Treat the current configured-handler smoke as Bash-payload-only proof; rely on existing tool permissions and do not claim native-PowerShell interception | #1497: add reviewed T4 native-PowerShell deny-policy coverage with direct allow and deny canaries before claiming interception | open |
| 2026-07-27 | blocker | ci/extended-workflow | CI Extended runs 30236731281 (job 89885846264) and 30237518666 (job 89888612738) both failed before checkout because the rhysd/actionlint@v1.7.12 Docker action ... | Treat both runs as missing Workflow Lint evidence, do not retry the same Docker bootstrap, and do not merge affected PRs until a direct pinned bootstrap passes ... | #1510: replace the Docker action with checksum-pinned Actionlint and Pyflakes downloads, explicit ShellCheck/Pyflakes paths, focused contract tests, and exact-h... | open |
| 2026-07-27 | pre_existing_noise | test/sqlite-concurrency | Correction to the #1373 resolution record: Required API Integration (windows-latest) on PR #1505 source head 6ee17a4849427d679722a9d1e034d4622536f4fe returned H... | Keep every recurrence red and use the bounded #1512 correlation/exception-classification diagnostics to capture the first server-side cause; do not retry the re... | #1373 resolved the proven #1282 SQLite registration-parity cause; successor #1512 remains open after its diagnostic-only slice until a recurrence identifies the... | open |
| 2026-07-27 | blocker | test/testcontainers-dockerless-skip | Taskdeck.Integration.Tests constructed its PostgreSQL Testcontainer in the collection-fixture constructor, so Testcontainers validated an unavailable Docker end... | Run the focused non-container projects while #1518 is in review; do not retry a known-hanging Docker probe merely to obtain a local full-suite verdict | #1518 defers PostgreSqlBuilder.Build until after DockerAvailableCheck succeeds, proves the unavailable path never invokes the factory, and retains Docker-backed... | resolved |

Expand Down
Loading
Loading