Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .claude/agents/gitgalaxy-pr-worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ You land one PR. The orchestrator gave you issue(s), acceptance criteria and coo
## Class sweep (before you code)
Fix the gap, not just the example (owner, 2026-10-11). The issue should carry a class table (issue-triage.md, "Class
sweep"); if it does not, build one: name the class, list its members from the authoritative source (CICS spec
`gitgalaxy/standards/cics/commands/`, `docs/language_status/cics_spec_status.md`, `det_survey.md`,
`gitgalaxy/standards/cics/commands/`, `docs/language_status/cics_spec_status.md` (not committed: `python tests/tools/generated_docs.py render`, or the `generated` branch), `det_survey.md`,
`construct_correspondence.md`, the register, the language's status page), and mark each handled / partial / missing /
out of scope with evidence.
- Members that share your mechanism (same handler, table or rule, and small: a few lines plus a test each) go in THIS
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/issue-triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ DOCUMENT family was missing too, and the owner had to argue for the siblings sep
or clause family (every `INSPECT` form), the data class (national / DBCS / multi-byte across code pages), the
construct family (every pipeline file format), the rule family (every unpinned-install form).
7. **List its members from the authoritative source**, not from memory:
- CICS commands: the spec `gitgalaxy/standards/cics/commands/<family>.py` and `docs/language_status/cics_spec_status.md`
- CICS commands: the spec `gitgalaxy/standards/cics/commands/<family>.py` and `docs/language_status/cics_spec_status.md` (rendered, not committed: `python tests/tools/generated_docs.py render` or the `generated` branch)
(and IBM's command reference for options the spec lacks).
- COBOL / det translation: `docs/language_status/det_survey.md`, `docs/language_status/construct_correspondence.md`,
the language register `docs/language_status/register/`.
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/blocker-slice/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ $PY tests/tools/proof_blockers.py SURVEY_DIR --label LABEL [--sweep SWEEP_DIR]
- **Crucible logs are never derived from the spec** (nor from a runtime or a port). The gen script is traced by
hand from IBM's documentation; `crucible_case.py check-hand-derived` fails if it imports anything but the stdlib
and `crucible_events`.
- `docs/language_status/cics_spec_status.md` is generated on main by the evidence-refresh bot (#4789): do NOT commit
it in a PR (`cics_spec_status.py render` only to look). After a slice, commit `refresh --census --crucible DIR`'s
- `docs/language_status/cics_spec_status.md` is git-ignored and published to the `generated` branch by generated-docs.yml
(#4789 / #5057): never commit it (`cics_spec_status.py render` only to look). After a slice, commit `refresh --census --crucible DIR`'s
`cics_spec_status.json`. A spec PR adds its row to `SPEC_PRS_DONE` there.
- The det-sweep coverage ledger is one file per case, `tests/equivalence/det_sweep_coverage/<case>.json` (#4789):
`det_coverage_ledger.py update <sweep DIR>` rewrites only the files of the cases that sweep ran.
Expand All @@ -72,7 +72,7 @@ $PY tests/tools/proof_blockers.py SURVEY_DIR --label LABEL [--sweep SWEEP_DIR]
numbers". The seed (EIBTASKN, 0 on both sides) is a stated fact of the run; a case that varies it states it on
both sides first. Seeds IBM does not allow are refused at run time by name.
- Every new assumption or refusal gets its register entry file (`docs/language_status/register/Xnn.md`, ID from
`register.py next X`; then `register.py render`) in the same PR.
`register.py next X`) in the same PR; the combined page is not committed (#5057).

## 4. After it lands

Expand Down
3 changes: 1 addition & 2 deletions .claude/skills/box-capacity/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ pytest, a `--jobs` sweep) reads `GG_JOB_CORES` the same way, never `os.cpu_count
agents append to (`tests/cobol_mainframe/test_det_translate.py`, `test_equivalence_cics.py`,
`tests/cics_crucible/test_cics_runtimes.py`): two PRs appending at the same anchor conflict; the second to merge keeps
both blocks.
- **Generated / ratchet files:** never hand-merge `docs/language_status/oracle_assumptions.md` (`register.py render`),
golden masters (`golden-lock.sh crucible_check.py --update --yes`), the ruff/mypy baselines (regenerate),
- **Generated / ratchet files:** golden masters (`golden-lock.sh crucible_check.py --update --yes`), the ruff/mypy baselines (regenerate),
`tests/equivalence/det_sweep_baseline.json` and the coverage ledger (their tools). Take main's side, regenerate.
- **Shared runtime changes** (`cobolrt/`, `DetCics`, the forge) move every port: one such PR in flight at a time, and its
`det_port.py check` list goes in the PR.
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/cics-command-slice/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Traps `--check` exists for:
- [ ] **Spec entry first** (`gitgalaxy/standards/cics`): promote the command's name-only entry to a full one
(options, refusals with reasons and register, groups, outcomes with RESP2, facts); `det/cics.py` and the stub
read it. The runtimes stay hand-written, and no crucible log is derived from the spec. Do not commit
`cics_spec_status.md` (#4789: the evidence-refresh bot renders it on main).
`cics_spec_status.md` (git-ignored; generated-docs.yml publishes it to `generated`, #5057).
- [ ] **Before survey** (now, on the unchanged branch): `$PY tests/tools/cics_census.py survey --out $SCRATCH/s
--label before --verb VERB` (det_survey.py, translation only; ~minutes per estate; background it with
`tests/tools/box/heavy-run.sh`).
Expand Down Expand Up @@ -75,7 +75,7 @@ Traps `--check` exists for:
- A divergence is a bug report against the runtime / translator, never a reason to edit the log.
- [ ] **Refusals registered:** a new X-number: `register.py next X` (take it when the issue is filed), then one file
`docs/language_status/register/Xnn.md` (front matter incl. the summary-table fields; body: ASSUMED / REFUSED, what
IBM says, which case proves it) and `register.py render`. Never edit `oracle_assumptions.md` by hand.
IBM says, which case proves it). `oracle_assumptions.md` is rendered, never committed (#5057).
- [ ] **After survey:** `... survey --out $SCRATCH/s --label after --verb VERB`, then
`$PY tests/tools/cics_census.py compare $SCRATCH/s --verb VERB`: per program translated / statements before ->
after, the holes left (deduped, line numbers stripped), "translated whole N -> M (non-burned a -> b)" and the
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/det-port/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Results:
| **runtime** | a `cobolrt` call is wrong for a value | DIVIDE's intermediate; TRIM of all spaces |
| **harness** | the input or the comparison differs between the sides, not the logic | LOW-VALUES dropped on the way to the DTO; PROGRAM-ID read from the sequence columns |
| **case** | a scenario is not what its name says | — |
| **oracle** | GnuCOBOL or our model is not IBM | add or update an entry file in `docs/language_status/register/`, then `register.py render` |
| **oracle** | GnuCOBOL or our model is not IBM | add or update an entry file in `docs/language_status/register/` (the page is rendered, not committed: #5057) |

A translator fix is never a hand edit of a port.

Expand Down
15 changes: 3 additions & 12 deletions .github/workflows/evidence-refresh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ name: Evidence Refresh
# Earlier bot PRs failed twice: #4640 was opened against a feature branch (the base is now pinned to main) and #4649
# went dirty while parallel PRs kept conflicting on the report (those PRs no longer commit it).
#
# #4789: the same for the CICS spec status page (docs/language_status/cics_spec_status.md): rendered here, never in a PR.
# #4789: the same for the CICS spec status page (docs/language_status/cics_spec_status.md), never in a PR; since #5057
# generated-docs.yml renders and publishes it after every merge (this job no longer touches it).
# The det-sweep coverage ledger is one file per case (tests/equivalence/det_sweep_coverage/<CASE>.json), so a case PR and
# this bot (or two case PRs) touch only the files of the cases they swept.
#
Expand Down Expand Up @@ -970,15 +971,6 @@ jobs:
path: gitgalaxy/docs/language_status/evidence_report
retention-days: 1

- name: Re-render the CICS spec status page (#4789)
# Derived output like the report above: PRs no longer commit docs/language_status/cics_spec_status.md (parallel
# slices conflicted on it); it is rendered here from main's spec, translator, stub and cics_spec_status.json.
if: always()
continue-on-error: true # a page that fails to render stays as main has it; it never holds back the records
run: |
cd gitgalaxy
python tests/tools/cics_spec_status.py render

- name: Summary
if: always()
run: |
Expand Down Expand Up @@ -1028,13 +1020,12 @@ jobs:
the records are rewritten from those runs (their pages are published from main to the `generated` branch by evidence-pages.yml, #4825). A proof that now fails is recorded as
not proven. The evidence reports (docs/language_status/evidence_report/) are re-rendered from them (#4703) and published to the `generated` branch, not committed (#4963),
the det-sweep coverage ledger (tests/equivalence/det_sweep_coverage/, one file per case: #4789) from the
sweep, and the CICS spec status page (docs/language_status/cics_spec_status.md, #4789) from main.
sweep. The CICS spec status page is published to the `generated` branch by generated-docs.yml (#5057).
Approvals are never written by this job. Auto-merge (squash) is enabled when every proof succeeded.
branch: auto/evidence-refresh${{ github.event_name != 'push' && '-full' || '' }} # a lane's own branch (#4743)
delete-branch: true
add-paths: |
tests/equivalence/det_sweep_coverage/*.json
docs/language_status/cics_spec_status.md
tests/equivalence/*/evidence.json
tests/cics_crucible/ports/*/*/evidence.json

Expand Down
147 changes: 147 additions & 0 deletions .github/workflows/generated-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: Generated Docs

# #5057 (the pattern of evidence-pages.yml #4825 and #4963): the aggregate pages rendered from committed sources --
# docs/language_status/oracle_assumptions.md (register entries, tests/tools/register.py) and
# docs/language_status/cics_spec_status.md (the CICS spec, translator, stub and cics_spec_status.json) -- are no longer
# committed. Every PR re-rendered and committed them, and parallel PRs conflicted on them for hours. The list of pages
# lives in tests/tools/generated_docs.py (PAGES).
#
# On a PR (render job, read-only, no write token): the pages must render, twice identically, from the PR's tree; the
# diff against a render of the PR's base goes to the job summary and the `generated-docs-diff` artifact, so a reviewer
# still sees the effect. On a push to main (every push, so the published pages always match main): the same render,
# then the publish job pushes them to the `generated` branch with tests/tools/generated_branch.py (a no-op when no page
# changed). Nothing here writes to main. Read the pages at:
# https://github.com/squid-protocol/gitgalaxy/tree/generated/docs/language_status
# Locally, `python tests/tools/generated_docs.py render` writes the same (git-ignored) pages into the checkout.
# First run: the push that merges this workflow publishes the first copies; workflow_dispatch from main re-publishes.

on:
pull_request:
paths:
- "docs/language_status/register/**"
- "docs/language_status/cics_spec_status.json"
- "docs/language_status/cics_command_spec.md"
- "gitgalaxy/standards/cics/**"
- "gitgalaxy/tools/cobol_to_java/det/**"
- "tests/tools/equivalence_*.py"
- "tests/tools/register.py"
- "tests/tools/cics_spec_status.py"
- "tests/tools/generated_docs.py"
- "tests/tools/generated_branch.py"
- ".github/workflows/generated-docs.yml"
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
# A PR's newer push cancels its older run; runs on main queue in order (never cancelled mid-publish), so an older
# render can never publish over a newer one.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
render:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: gitgalaxy
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: |
gitgalaxy/pyproject.toml
gitgalaxy/ci/requirements/*.txt

- name: Install GitGalaxy (+ the translator's parser, read by cics_spec_status)
run: |
python -m pip install --require-hashes -r gitgalaxy/ci/requirements/bootstrap.txt
pip install --require-hashes -r gitgalaxy/ci/requirements/treesitter.txt
pip install --no-build-isolation -e ./gitgalaxy

- name: Render the pages (must succeed and be deterministic)
env:
GITGALAXY_LICENSE_KEY: COMMUNITY_FREE_TIER
run: |
cd gitgalaxy
PYTHONPATH="$PWD" python tests/tools/generated_docs.py check --out "$RUNNER_TEMP/pages"

- name: Checkout the PR's base
if: github.event_name == 'pull_request'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: base
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false

- name: Diff against the base's pages (job summary)
if: github.event_name == 'pull_request'
env:
GITGALAXY_LICENSE_KEY: COMMUNITY_FREE_TIER
run: |
mkdir -p "$RUNNER_TEMP/base-pages"
if [ -f base/tests/tools/generated_docs.py ]; then
# the base's own renderers (they put their checkout first on sys.path)
(cd base && PYTHONPATH="$PWD" python tests/tools/generated_docs.py check --out "$RUNNER_TEMP/base-pages") \
|| echo "::warning title=Generated docs::the base does not render; the diff is against nothing"
else # a base from before #5057 still committed the pages
(cd base && for f in docs/language_status/oracle_assumptions.md docs/language_status/cics_spec_status.md; do
[ -f "$f" ] && mkdir -p "$RUNNER_TEMP/base-pages/$(dirname "$f")" && cp "$f" "$RUNNER_TEMP/base-pages/$f"; done) || true
fi
python gitgalaxy/tests/tools/generated_docs.py diff "$RUNNER_TEMP/base-pages" "$RUNNER_TEMP/pages" > "$RUNNER_TEMP/pages/DIFF.md"
cat "$RUNNER_TEMP/pages/DIFF.md" >> "$GITHUB_STEP_SUMMARY"

- name: Keep the diff and the rendered pages (PR)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: generated-docs-diff
path: ${{ runner.temp }}/pages
retention-days: 7

- name: Keep the rendered pages for the publish job (main)
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: generated-docs
path: ${{ runner.temp }}/pages
retention-days: 1

# A separate job so the job that runs PR code never holds a write token (#4963). Main's code only.
publish:
needs: [render]
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write # push to the `generated` branch only
steps:
- name: Checkout main
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: main
persist-credentials: true # the publish step pushes to `generated` with this token; no PR code runs here

- name: Download the rendered pages
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: generated-docs
path: main

- name: Publish the pages to the generated branch
run: |
cd main
python tests/tools/generated_branch.py publish --stamp generated-docs \
--message "generated docs as of main $GITHUB_SHA" \
docs/language_status/oracle_assumptions.md \
docs/language_status/cics_spec_status.md
echo "published the generated pages from main $GITHUB_SHA: https://github.com/${GITHUB_REPOSITORY}/tree/generated/docs/language_status" >> "$GITHUB_STEP_SUMMARY"
11 changes: 0 additions & 11 deletions .github/workflows/smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,6 @@ jobs:
continue-on-error: true
run: python tests/tools/evidence_report.py --deltas --live >> "$GITHUB_STEP_SUMMARY"

- name: CICS spec status page (advisory, #4789)
if: always() && matrix.group == 3 # part 1 runs the entry-point checks (#4829 balance)
continue-on-error: true
run: |
{
echo "## CICS spec status page (advisory)"
if python tests/tools/cics_spec_status.py render --check 2>&1; then :; else
echo "The evidence-refresh bot re-renders docs/language_status/cics_spec_status.md on main after merge; do not commit it here."
fi
} >> "$GITHUB_STEP_SUMMARY"

# #4847: the nightly's three parts' durations, merged (pytest-split's {nodeid: seconds} files, disjoint) and saved
# under `test-durations-<run id>`; the next run of every part restores the newest one. Not a required check.
full-suite-durations:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ tests/telemetry_out/
# #4825: the per-program evidence pages are rendered from the records and published to the `generated` branch by
# .github/workflows/evidence-pages.yml; main never commits them (PRs collided on them).
docs/language_status/evidence/
# #5057: the aggregate pages rendered from committed sources (tests/tools/generated_docs.py) are published to the
# `generated` branch by .github/workflows/generated-docs.yml; PRs commit their sources only (they collided on the pages).
docs/language_status/oracle_assumptions.md
docs/language_status/cics_spec_status.md

# #4980: fetched by equivalence_db2.fetch_odbc_cli() into the Docker build context; never committed
tests/equivalence/linuxx64_odbc_cli.tar.gz
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ proves the result (batch, CICS and Db2 cases). Use the `det-port` skill: it cove
the Db2 container), debugging a differing scenario, and the checklists for a translator, runtime, harness or oracle
change. After a translator change, `det_port.py check --work DIR` lists the ports it moved against `origin/main`;
re-prove exactly those. Every known or suspected difference between our oracle (GnuCOBOL plus our CICS, Db2 and LE
models) and IBM z/OS is in `docs/language_status/oracle_assumptions.md`; a new model or refusal adds an entry file under `docs/language_status/register/` (ID from `python tests/tools/register.py next X`), then `register.py render` regenerates that page (never hand-edit it; CI checks it).
models) and IBM z/OS is in `docs/language_status/oracle_assumptions.md`; a new model or refusal adds an entry file under `docs/language_status/register/` (ID from `python tests/tools/register.py next X`), and that file is all the PR commits: the page is rendered, never committed (#5057; `generated-docs.yml` publishes it to the `generated` branch, `register.py render` writes a local copy).

## Testing conventions

Expand Down
Loading
Loading