gabion 0.1.0__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gabion-0.1.5/.github/workflows/auto-test-tag.yml +72 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/workflows/ci.yml +31 -14
- gabion-0.1.5/.github/workflows/mirror-next.yml +32 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/workflows/pr-dataflow-grammar.yml +63 -5
- gabion-0.1.5/.github/workflows/promote-release.yml +64 -0
- gabion-0.1.5/.github/workflows/release-pypi.yml +89 -0
- gabion-0.1.5/.github/workflows/release-tag.yml +30 -0
- gabion-0.1.5/.github/workflows/release-testpypi.yml +92 -0
- {gabion-0.1.0 → gabion-0.1.5}/.gitignore +1 -0
- {gabion-0.1.0 → gabion-0.1.5}/AGENTS.md +7 -1
- {gabion-0.1.0 → gabion-0.1.5}/CONTRIBUTING.md +34 -6
- {gabion-0.1.0 → gabion-0.1.5}/PKG-INFO +21 -4
- {gabion-0.1.0 → gabion-0.1.5}/POLICY_SEED.md +101 -2
- {gabion-0.1.0 → gabion-0.1.5}/README.md +15 -3
- gabion-0.1.5/baselines/dataflow_baseline.txt +5 -0
- {gabion-0.1.0 → gabion-0.1.5}/docs/allowed_actions.txt +1 -0
- gabion-0.1.5/docs/coverage_semantics.md +134 -0
- gabion-0.1.5/docs/influence_index.md +59 -0
- {gabion-0.1.0 → gabion-0.1.5}/docs/publishing_practices.md +40 -1
- {gabion-0.1.0 → gabion-0.1.5}/docs/sppf_checklist.md +13 -5
- {gabion-0.1.0 → gabion-0.1.5}/docs/synthesis_payload.md +5 -2
- gabion-0.1.5/gabion.toml +7 -0
- gabion-0.1.5/glossary.md +679 -0
- gabion-0.1.5/out/out-1.md +98 -0
- gabion-0.1.5/out/out-2.md +171 -0
- {gabion-0.1.0 → gabion-0.1.5}/pyproject.toml +9 -1
- gabion-0.1.5/pytest.ini +3 -0
- gabion-0.1.5/requirements.lock +75 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/checks.sh +5 -1
- {gabion-0.1.0 → gabion-0.1.5}/scripts/docflow_audit.py +94 -4
- {gabion-0.1.0 → gabion-0.1.5}/scripts/pin_actions.py +1 -1
- {gabion-0.1.0 → gabion-0.1.5}/scripts/policy_check.py +260 -5
- gabion-0.1.5/scripts/release_read_project_version.py +33 -0
- gabion-0.1.5/scripts/release_set_test_version.py +58 -0
- gabion-0.1.5/scripts/release_tag.py +86 -0
- gabion-0.1.5/scripts/release_verify_pypi_tag.py +75 -0
- gabion-0.1.5/scripts/release_verify_test_tag.py +38 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/__init__.py +1 -1
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/analysis/dataflow_audit.py +315 -88
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/analysis/visitors.py +80 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/cli.py +367 -144
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/config.py +8 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/lsp_client.py +3 -2
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/refactor/engine.py +214 -23
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/refactor/model.py +1 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/schema.py +2 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/server.py +10 -7
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/merge.py +0 -2
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/model.py +1 -0
- gabion-0.1.5/tests/test_alias_return_propagation.py +48 -0
- gabion-0.1.5/tests/test_cli_commands.py +275 -0
- gabion-0.1.5/tests/test_cli_helpers.py +164 -0
- gabion-0.1.5/tests/test_cli_payloads.py +170 -0
- gabion-0.1.5/tests/test_config_edges.py +23 -0
- gabion-0.1.5/tests/test_constant_flow_audit.py +150 -0
- gabion-0.1.5/tests/test_dataflow_audit_edges.py +768 -0
- gabion-0.1.5/tests/test_dataflow_audit_flows.py +155 -0
- gabion-0.1.5/tests/test_dataflow_audit_run.py +112 -0
- gabion-0.1.5/tests/test_dataflow_class_resolution.py +100 -0
- gabion-0.1.5/tests/test_dataflow_dataclass_bundles.py +150 -0
- gabion-0.1.5/tests/test_dataflow_grouping.py +97 -0
- gabion-0.1.5/tests/test_dataflow_helpers.py +453 -0
- gabion-0.1.5/tests/test_dataflow_kitchen_sink.py +192 -0
- gabion-0.1.5/tests/test_dataflow_main.py +26 -0
- gabion-0.1.5/tests/test_dataflow_misc_edges.py +51 -0
- gabion-0.1.5/tests/test_dataflow_report_helpers.py +107 -0
- gabion-0.1.5/tests/test_dataflow_resolve_callee.py +272 -0
- gabion-0.1.5/tests/test_dataflow_run.py +124 -0
- gabion-0.1.5/tests/test_dataflow_run_edges.py +316 -0
- gabion-0.1.5/tests/test_knob_merge.py +48 -0
- gabion-0.1.5/tests/test_lsp_client_errors.py +21 -0
- gabion-0.1.5/tests/test_lsp_client_rpc.py +81 -0
- gabion-0.1.5/tests/test_lsp_client_run_command_di.py +59 -0
- gabion-0.1.5/tests/test_misc_coverage.py +156 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_refactor_engine.py +32 -0
- gabion-0.1.5/tests/test_refactor_engine_edges.py +129 -0
- gabion-0.1.5/tests/test_refactor_engine_helpers.py +108 -0
- gabion-0.1.5/tests/test_refactor_engine_more.py +320 -0
- gabion-0.1.5/tests/test_refactor_idempotency.py +87 -0
- gabion-0.1.5/tests/test_server_execute_command.py +136 -0
- gabion-0.1.5/tests/test_server_execute_command_edges.py +232 -0
- gabion-0.1.5/tests/test_server_helpers.py +55 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_merge.py +6 -4
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_naming.py +13 -4
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_protocols.py +15 -0
- gabion-0.1.5/tests/test_type_flow_audit.py +52 -0
- gabion-0.1.5/tests/test_unused_arg_audit.py +189 -0
- gabion-0.1.5/tests/test_visitors_edges.py +409 -0
- gabion-0.1.5/tests/test_visitors_unit.py +187 -0
- gabion-0.1.0/.github/workflows/release-test.yml +0 -34
- gabion-0.1.0/.github/workflows/release.yml +0 -32
- gabion-0.1.0/gabion.toml +0 -4
- gabion-0.1.0/glossary.md +0 -221
- gabion-0.1.0/pytest.ini +0 -2
- gabion-0.1.0/tests/test_unused_arg_audit.py +0 -92
- {gabion-0.1.0 → gabion-0.1.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/ISSUE_TEMPLATE/sppf-node.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/actions/gabion/README.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/actions/gabion/action.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/.github/actions/gabion/run.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/LICENSE +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/Makefile +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/artifacts/.gitkeep +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/docs/doer_judge_witness.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/docs/pinning_actions.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/docs/workflows/gabion_action_example.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/extensions/vscode/README.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/extensions/vscode/extension.js +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/extensions/vscode/package.json +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/AGENTS.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/CONTRIBUTING.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/README.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/ci-milestones.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/dataflow_grammar_audit.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-1.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-10.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-11.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-12.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-13.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-14.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-2.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-3.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-4.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-5.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-6.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-7.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-8.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/in-9.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/inspiration.md +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/policy_check.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/in/pr-dataflow-grammar.yml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/mise.toml +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/audit_snapshot.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/bootstrap.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/clean_artifacts.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/dataflow_grammar_audit.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/install_hooks.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/latest_snapshot.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/lsp_smoke_test.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/run_tests.sh +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/scripts/sppf_sync.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/__main__.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/analysis/__init__.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/analysis/engine.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/analysis/model.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/refactor/__init__.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/__init__.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/naming.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/protocols.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/src/gabion/synthesis/schedule.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_alias_attribute.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_alias_rename_invariance.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_alias_unpacking.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_baseline_ratchet.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_class_method_propagation.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_code_action_stub.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_config_declarations_anywhere.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_config_defaults.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_config_fields.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_dataclass_call_bundles.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_decorator_transparency.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_import_shadowing.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_lsp_smoke.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_nested_resolution.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_param_spans.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_refactor_plan.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_star_import_resolution.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_merge_integration.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_schedule.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_stubs.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_tiers.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_synthesis_types.py +0 -0
- {gabion-0.1.0 → gabion-0.1.5}/tests/test_wildcard_forwarding.py +0 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: auto-test-tag
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: ["mirror-next"]
|
|
6
|
+
types: [completed]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
tag:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
if: >
|
|
15
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
16
|
+
github.event.workflow_run.head_branch == 'main' &&
|
|
17
|
+
(github.event.workflow_run.actor.login == github.repository_owner ||
|
|
18
|
+
github.event.workflow_run.actor.login == 'github-actions[bot]')
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
24
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
- name: Verify next mirrors main
|
|
28
|
+
run: |
|
|
29
|
+
git fetch origin main next --tags
|
|
30
|
+
RUN_SHA=$(git rev-parse HEAD)
|
|
31
|
+
MAIN_SHA=$(git rev-parse origin/main)
|
|
32
|
+
NEXT_SHA=$(git rev-parse origin/next)
|
|
33
|
+
if [ "$RUN_SHA" != "$MAIN_SHA" ]; then
|
|
34
|
+
echo "Next must mirror main before tagging."
|
|
35
|
+
echo "workflow=$RUN_SHA"
|
|
36
|
+
echo "main=$MAIN_SHA"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
if [ "$NEXT_SHA" != "$MAIN_SHA" ]; then
|
|
40
|
+
echo "Next must mirror main before tagging."
|
|
41
|
+
echo "next=$NEXT_SHA"
|
|
42
|
+
echo "main=$MAIN_SHA"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
- name: Read version
|
|
46
|
+
id: version
|
|
47
|
+
run: python scripts/release_read_project_version.py --output "$GITHUB_OUTPUT"
|
|
48
|
+
- name: Create test tag if missing
|
|
49
|
+
id: tag
|
|
50
|
+
run: |
|
|
51
|
+
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
52
|
+
TAG="test-v${{ steps.version.outputs.version }}+${STAMP}"
|
|
53
|
+
TARGET="$(git rev-parse origin/next)"
|
|
54
|
+
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
|
|
55
|
+
echo "Tag already exists: $TAG"
|
|
56
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
git config user.name "github-actions[bot]"
|
|
60
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
61
|
+
git tag -a "$TAG" -m "Test release $TAG" "$TARGET"
|
|
62
|
+
git push origin "refs/tags/$TAG"
|
|
63
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
64
|
+
- name: Write tag artifact
|
|
65
|
+
if: steps.tag.outputs.tag != ''
|
|
66
|
+
run: echo "${{ steps.tag.outputs.tag }}" > tag.txt
|
|
67
|
+
- name: Upload tag artifact
|
|
68
|
+
if: steps.tag.outputs.tag != ''
|
|
69
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
70
|
+
with:
|
|
71
|
+
name: auto-test-tag
|
|
72
|
+
path: tag.txt
|
|
@@ -4,9 +4,6 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
6
|
- stage
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- main
|
|
10
7
|
workflow_dispatch:
|
|
11
8
|
|
|
12
9
|
permissions:
|
|
@@ -26,14 +23,18 @@ jobs:
|
|
|
26
23
|
uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8
|
|
27
24
|
- name: Install toolchain
|
|
28
25
|
run: mise install
|
|
29
|
-
- name:
|
|
30
|
-
run: mise exec -- python -m pip install -e .
|
|
31
|
-
- name: Install test deps
|
|
32
|
-
run: mise exec -- python -m pip install pytest
|
|
33
|
-
- name: Policy check (workflows)
|
|
26
|
+
- name: Create venv
|
|
34
27
|
run: |
|
|
35
|
-
mise exec -- python -m
|
|
36
|
-
|
|
28
|
+
mise exec -- python -m venv .venv
|
|
29
|
+
echo "VIRTUAL_ENV=$PWD/.venv" >> $GITHUB_ENV
|
|
30
|
+
echo "$PWD/.venv/bin" >> $GITHUB_PATH
|
|
31
|
+
- name: Install dependencies (locked)
|
|
32
|
+
run: |
|
|
33
|
+
.venv/bin/python -m pip install --upgrade pip uv
|
|
34
|
+
.venv/bin/uv pip sync requirements.lock
|
|
35
|
+
.venv/bin/uv pip install -e .
|
|
36
|
+
- name: Policy check (workflows)
|
|
37
|
+
run: .venv/bin/python scripts/policy_check.py --workflows
|
|
37
38
|
- name: Policy check (posture)
|
|
38
39
|
if: github.event_name == 'push'
|
|
39
40
|
env:
|
|
@@ -43,15 +44,25 @@ jobs:
|
|
|
43
44
|
echo "POLICY_GITHUB_TOKEN not set; skipping posture check."
|
|
44
45
|
exit 0
|
|
45
46
|
fi
|
|
46
|
-
|
|
47
|
+
.venv/bin/python scripts/policy_check.py --posture
|
|
47
48
|
- name: Dataflow audit
|
|
48
|
-
run:
|
|
49
|
+
run: |
|
|
50
|
+
mkdir -p artifacts/audit_reports
|
|
51
|
+
.venv/bin/python -m gabion check \
|
|
52
|
+
--report artifacts/audit_reports/dataflow_report.md \
|
|
53
|
+
--baseline baselines/dataflow_baseline.txt \
|
|
54
|
+
|| (cat artifacts/audit_reports/dataflow_report.md; exit 1)
|
|
49
55
|
- name: Docflow audit
|
|
50
|
-
run:
|
|
56
|
+
run: .venv/bin/python scripts/docflow_audit.py --root . --fail-on-violations
|
|
51
57
|
- name: Tests
|
|
52
58
|
run: |
|
|
53
59
|
mkdir -p artifacts/test_runs
|
|
54
|
-
|
|
60
|
+
.venv/bin/python -m pytest \
|
|
61
|
+
--cov=src/gabion \
|
|
62
|
+
--cov-report=term-missing \
|
|
63
|
+
--cov-report=xml:artifacts/test_runs/coverage.xml \
|
|
64
|
+
--cov-report=html:artifacts/test_runs/htmlcov \
|
|
65
|
+
--cov-fail-under=100 \
|
|
55
66
|
--junitxml artifacts/test_runs/junit.xml \
|
|
56
67
|
--log-file artifacts/test_runs/pytest.log \
|
|
57
68
|
--log-file-level=INFO
|
|
@@ -61,3 +72,9 @@ jobs:
|
|
|
61
72
|
with:
|
|
62
73
|
name: test-runs
|
|
63
74
|
path: artifacts/test_runs
|
|
75
|
+
- name: Upload dataflow report
|
|
76
|
+
if: always()
|
|
77
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
78
|
+
with:
|
|
79
|
+
name: dataflow-report
|
|
80
|
+
path: artifacts/audit_reports/dataflow_report.md
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: mirror-next
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
mirror:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
if: github.ref == 'refs/heads/main' && github.actor == github.repository_owner
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
- name: Mirror main to next
|
|
20
|
+
run: |
|
|
21
|
+
git fetch origin main next
|
|
22
|
+
HEAD_SHA=$(git rev-parse HEAD)
|
|
23
|
+
MAIN_SHA=$(git rev-parse origin/main)
|
|
24
|
+
if [ "$HEAD_SHA" != "$MAIN_SHA" ]; then
|
|
25
|
+
echo "Mirror blocked: workflow SHA must equal current main."
|
|
26
|
+
echo "workflow=$HEAD_SHA"
|
|
27
|
+
echo "main=$MAIN_SHA"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
git config user.name "github-actions[bot]"
|
|
31
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
32
|
+
git push --force-with-lease origin "$HEAD_SHA":refs/heads/next
|
|
@@ -2,11 +2,8 @@ name: pr-dataflow-grammar
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
|
-
|
|
6
|
-
-
|
|
7
|
-
- "src/**"
|
|
8
|
-
- "gabion.toml"
|
|
9
|
-
- ".github/workflows/pr-dataflow-grammar.yml"
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
10
7
|
|
|
11
8
|
permissions:
|
|
12
9
|
contents: read
|
|
@@ -15,6 +12,7 @@ jobs:
|
|
|
15
12
|
dataflow-grammar:
|
|
16
13
|
runs-on: ubuntu-latest
|
|
17
14
|
permissions:
|
|
15
|
+
actions: read
|
|
18
16
|
contents: read
|
|
19
17
|
pull-requests: write
|
|
20
18
|
env:
|
|
@@ -26,6 +24,66 @@ jobs:
|
|
|
26
24
|
uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8
|
|
27
25
|
- name: Install toolchain
|
|
28
26
|
run: mise install
|
|
27
|
+
- name: Verify stage CI succeeded for this SHA
|
|
28
|
+
env:
|
|
29
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
REPO: ${{ github.repository }}
|
|
31
|
+
SHA: ${{ github.event.pull_request.head.sha }}
|
|
32
|
+
run: |
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
python - <<'PY'
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import time
|
|
38
|
+
import urllib.request
|
|
39
|
+
|
|
40
|
+
token = os.environ["GITHUB_TOKEN"]
|
|
41
|
+
repo = os.environ["REPO"]
|
|
42
|
+
sha = os.environ["SHA"]
|
|
43
|
+
deadline = time.time() + 20 * 60
|
|
44
|
+
url = (
|
|
45
|
+
f"https://api.github.com/repos/{repo}/actions/workflows/ci.yml/runs"
|
|
46
|
+
f"?branch=stage&per_page=50"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
while True:
|
|
50
|
+
req = urllib.request.Request(
|
|
51
|
+
url,
|
|
52
|
+
headers={
|
|
53
|
+
"Authorization": f"Bearer {token}",
|
|
54
|
+
"Accept": "application/vnd.github+json",
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
with urllib.request.urlopen(req) as resp:
|
|
58
|
+
payload = json.loads(resp.read().decode("utf-8"))
|
|
59
|
+
|
|
60
|
+
runs = payload.get("workflow_runs", [])
|
|
61
|
+
match = next((r for r in runs if r.get("head_sha") == sha), None)
|
|
62
|
+
if match is None:
|
|
63
|
+
if time.time() > deadline:
|
|
64
|
+
raise SystemExit(
|
|
65
|
+
f"Stage CI has not run for {sha}. Push to stage and wait for CI."
|
|
66
|
+
)
|
|
67
|
+
time.sleep(15)
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
status = match.get("status")
|
|
71
|
+
if status != "completed":
|
|
72
|
+
if time.time() > deadline:
|
|
73
|
+
raise SystemExit(
|
|
74
|
+
f"Stage CI for {sha} not complete (status={status})."
|
|
75
|
+
)
|
|
76
|
+
time.sleep(15)
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
conclusion = match.get("conclusion")
|
|
80
|
+
if conclusion != "success":
|
|
81
|
+
raise SystemExit(
|
|
82
|
+
f"Stage CI for {sha} not successful (conclusion={conclusion})."
|
|
83
|
+
)
|
|
84
|
+
print(f"Stage CI OK for {sha}.")
|
|
85
|
+
break
|
|
86
|
+
PY
|
|
29
87
|
- name: Install package
|
|
30
88
|
run: mise exec -- python -m pip install -e .
|
|
31
89
|
- name: Render dataflow grammar report
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: promote-release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: ["release-testpypi"]
|
|
6
|
+
types: [completed]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
actions: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
promote:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
if: >
|
|
16
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
17
|
+
(github.event.workflow_run.actor.login == github.repository_owner ||
|
|
18
|
+
github.event.workflow_run.actor.login == 'github-actions[bot]')
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
24
|
+
- name: Download test tag artifact
|
|
25
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
26
|
+
with:
|
|
27
|
+
name: release-testpypi-tag
|
|
28
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
29
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
path: artifacts/release-testpypi
|
|
31
|
+
- name: Promote next to release
|
|
32
|
+
run: |
|
|
33
|
+
git fetch origin main next release --tags
|
|
34
|
+
TAG=""
|
|
35
|
+
TAG_FILE=""
|
|
36
|
+
if [ -d artifacts/release-testpypi ]; then
|
|
37
|
+
TAG_FILE="$(find artifacts/release-testpypi -name tag.txt | head -n 1 || true)"
|
|
38
|
+
fi
|
|
39
|
+
if [ -n "$TAG_FILE" ] && [ -f "$TAG_FILE" ]; then
|
|
40
|
+
TAG="$(cat "$TAG_FILE")"
|
|
41
|
+
elif [[ "${{ github.event.workflow_run.head_branch }}" == test-v* ]]; then
|
|
42
|
+
TAG="${{ github.event.workflow_run.head_branch }}"
|
|
43
|
+
fi
|
|
44
|
+
if [ -z "$TAG" ]; then
|
|
45
|
+
echo "Missing test tag for promotion."
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
HEAD_SHA=$(git rev-parse HEAD)
|
|
49
|
+
NEXT_SHA=$(git rev-parse origin/next)
|
|
50
|
+
TAG_SHA=$(git rev-parse "refs/tags/$TAG^{commit}")
|
|
51
|
+
if [ "$HEAD_SHA" != "$TAG_SHA" ]; then
|
|
52
|
+
echo "Workflow head sha must match tag."
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
if [ "$NEXT_SHA" != "$HEAD_SHA" ]; then
|
|
56
|
+
echo "Next must mirror tested commit before promoting release."
|
|
57
|
+
echo "next=$NEXT_SHA"
|
|
58
|
+
echo "tested=$HEAD_SHA"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
git merge-base --is-ancestor "$HEAD_SHA" origin/main
|
|
62
|
+
git config user.name "github-actions[bot]"
|
|
63
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
64
|
+
git push --force-with-lease origin "$HEAD_SHA":refs/heads/release
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
name: release-pypi
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- "v*"
|
|
6
|
+
- "!test-v*"
|
|
7
|
+
workflow_run:
|
|
8
|
+
workflows: ["release-tag"]
|
|
9
|
+
types: [completed]
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
actions: read
|
|
13
|
+
id-token: write
|
|
14
|
+
jobs:
|
|
15
|
+
publish:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
if: >
|
|
18
|
+
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
|
|
19
|
+
(github.event_name == 'workflow_run' &&
|
|
20
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
21
|
+
(github.event.workflow_run.actor.login == github.repository_owner ||
|
|
22
|
+
github.event.workflow_run.actor.login == 'github-actions[bot]'))
|
|
23
|
+
environment: pypi
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
|
|
29
|
+
- name: Download release tag artifact
|
|
30
|
+
if: github.event_name == 'workflow_run'
|
|
31
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
32
|
+
with:
|
|
33
|
+
name: release-pypi-tag
|
|
34
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
35
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
36
|
+
path: artifacts/release-pypi
|
|
37
|
+
- name: Resolve release tag
|
|
38
|
+
id: tag
|
|
39
|
+
run: |
|
|
40
|
+
if [ "${{ github.event_name }}" = "push" ]; then
|
|
41
|
+
echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
if [ ! -f artifacts/release-pypi/tag.txt ]; then
|
|
45
|
+
echo "No tag artifact found; skipping."
|
|
46
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
TAG="$(cat artifacts/release-pypi/tag.txt)"
|
|
50
|
+
if [ -z "$TAG" ]; then
|
|
51
|
+
echo "Empty tag; skipping."
|
|
52
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
56
|
+
- name: Persist release tag
|
|
57
|
+
if: steps.tag.outputs.tag != ''
|
|
58
|
+
run: |
|
|
59
|
+
mkdir -p artifacts/release-pypi
|
|
60
|
+
echo "${{ steps.tag.outputs.tag }}" > artifacts/release-pypi/tag.txt
|
|
61
|
+
- name: Upload release tag artifact
|
|
62
|
+
if: steps.tag.outputs.tag != ''
|
|
63
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
64
|
+
with:
|
|
65
|
+
name: release-pypi-tag
|
|
66
|
+
path: artifacts/release-pypi/tag.txt
|
|
67
|
+
- name: Verify release tag provenance + version
|
|
68
|
+
if: steps.tag.outputs.tag != ''
|
|
69
|
+
run: python scripts/release_verify_pypi_tag.py --tag "${{ steps.tag.outputs.tag }}"
|
|
70
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
|
|
71
|
+
if: steps.tag.outputs.tag != ''
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.11"
|
|
74
|
+
- name: Build
|
|
75
|
+
if: steps.tag.outputs.tag != ''
|
|
76
|
+
run: |
|
|
77
|
+
python -m pip install --upgrade pip
|
|
78
|
+
python -m pip install build
|
|
79
|
+
python -m build
|
|
80
|
+
- name: Verify dist metadata
|
|
81
|
+
if: steps.tag.outputs.tag != ''
|
|
82
|
+
run: |
|
|
83
|
+
python -m pip install --upgrade twine pkginfo
|
|
84
|
+
python -m twine check dist/*
|
|
85
|
+
- name: Publish to PyPI
|
|
86
|
+
if: steps.tag.outputs.tag != ''
|
|
87
|
+
uses: pypa/gh-action-pypi-publish@03f86fee9ac21f854951f5c6e2a02c2a1324aec7
|
|
88
|
+
with:
|
|
89
|
+
verify-metadata: false
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: release-tag
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
tag:
|
|
7
|
+
description: "Release tag to create (vX.Y.Z or test-vX.Y.Z)"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
tag:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
if: (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/next') && github.actor == github.repository_owner
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- name: Create and push tag
|
|
23
|
+
run: python scripts/release_tag.py --tag "${{ inputs.tag }}"
|
|
24
|
+
- name: Write release tag artifact
|
|
25
|
+
run: echo "${{ inputs.tag }}" > tag.txt
|
|
26
|
+
- name: Upload release tag artifact
|
|
27
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
28
|
+
with:
|
|
29
|
+
name: release-pypi-tag
|
|
30
|
+
path: tag.txt
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
name: release-testpypi
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- "test-v*"
|
|
6
|
+
workflow_run:
|
|
7
|
+
workflows: ["auto-test-tag"]
|
|
8
|
+
types: [completed]
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
actions: read
|
|
12
|
+
id-token: write
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
if: >
|
|
17
|
+
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/test-v')) ||
|
|
18
|
+
(github.event_name == 'workflow_run' &&
|
|
19
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
20
|
+
(github.event.workflow_run.actor.login == github.repository_owner ||
|
|
21
|
+
github.event.workflow_run.actor.login == 'github-actions[bot]'))
|
|
22
|
+
environment: testpypi
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
25
|
+
with:
|
|
26
|
+
fetch-depth: 0
|
|
27
|
+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
|
|
28
|
+
- name: Download tag artifact
|
|
29
|
+
if: github.event_name == 'workflow_run'
|
|
30
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
31
|
+
with:
|
|
32
|
+
name: auto-test-tag
|
|
33
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
34
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
35
|
+
path: artifacts/auto-test-tag
|
|
36
|
+
- name: Resolve test tag
|
|
37
|
+
id: tag
|
|
38
|
+
run: |
|
|
39
|
+
if [ "${{ github.event_name }}" = "push" ]; then
|
|
40
|
+
echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
if [ ! -f artifacts/auto-test-tag/tag.txt ]; then
|
|
44
|
+
echo "No tag artifact found; skipping."
|
|
45
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
TAG="$(cat artifacts/auto-test-tag/tag.txt)"
|
|
49
|
+
if [ -z "$TAG" ]; then
|
|
50
|
+
echo "Empty tag; skipping."
|
|
51
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
55
|
+
- name: Persist test tag
|
|
56
|
+
if: steps.tag.outputs.tag != ''
|
|
57
|
+
run: |
|
|
58
|
+
mkdir -p artifacts/release-testpypi
|
|
59
|
+
echo "${{ steps.tag.outputs.tag }}" > artifacts/release-testpypi/tag.txt
|
|
60
|
+
- name: Upload test tag artifact
|
|
61
|
+
if: steps.tag.outputs.tag != ''
|
|
62
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
63
|
+
with:
|
|
64
|
+
name: release-testpypi-tag
|
|
65
|
+
path: artifacts/release-testpypi/tag.txt
|
|
66
|
+
- name: Ensure tag is on main/next
|
|
67
|
+
if: steps.tag.outputs.tag != ''
|
|
68
|
+
run: python scripts/release_verify_test_tag.py --tag "${{ steps.tag.outputs.tag }}"
|
|
69
|
+
- name: Set version from test tag
|
|
70
|
+
if: steps.tag.outputs.tag != ''
|
|
71
|
+
run: python scripts/release_set_test_version.py --tag "${{ steps.tag.outputs.tag }}"
|
|
72
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
|
|
73
|
+
if: steps.tag.outputs.tag != ''
|
|
74
|
+
with:
|
|
75
|
+
python-version: "3.11"
|
|
76
|
+
- name: Build
|
|
77
|
+
if: steps.tag.outputs.tag != ''
|
|
78
|
+
run: |
|
|
79
|
+
python -m pip install --upgrade pip
|
|
80
|
+
python -m pip install build
|
|
81
|
+
python -m build
|
|
82
|
+
- name: Verify dist metadata
|
|
83
|
+
if: steps.tag.outputs.tag != ''
|
|
84
|
+
run: |
|
|
85
|
+
python -m pip install --upgrade twine pkginfo
|
|
86
|
+
python -m twine check dist/*
|
|
87
|
+
- name: Publish to TestPyPI
|
|
88
|
+
if: steps.tag.outputs.tag != ''
|
|
89
|
+
uses: pypa/gh-action-pypi-publish@03f86fee9ac21f854951f5c6e2a02c2a1324aec7
|
|
90
|
+
with:
|
|
91
|
+
repository-url: https://test.pypi.org/legacy/
|
|
92
|
+
verify-metadata: false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
doc_revision:
|
|
2
|
+
doc_revision: 12
|
|
3
3
|
reader_reintern: "Reader-only: re-intern if doc_revision changed since you last read this doc."
|
|
4
4
|
doc_id: agents
|
|
5
5
|
doc_role: agent
|
|
@@ -13,6 +13,11 @@ doc_requires:
|
|
|
13
13
|
- CONTRIBUTING.md
|
|
14
14
|
- POLICY_SEED.md
|
|
15
15
|
- glossary.md
|
|
16
|
+
doc_reviewed_as_of:
|
|
17
|
+
README.md: 58
|
|
18
|
+
CONTRIBUTING.md: 69
|
|
19
|
+
POLICY_SEED.md: 28
|
|
20
|
+
glossary.md: 13
|
|
16
21
|
doc_change_protocol: "POLICY_SEED.md §6"
|
|
17
22
|
doc_invariants:
|
|
18
23
|
- read_policy_glossary_first
|
|
@@ -62,5 +67,6 @@ Semantic correctness is governed by `glossary.md` (co-equal contract).
|
|
|
62
67
|
## Doc hygiene
|
|
63
68
|
- Markdown docs include a YAML front-matter block with `doc_revision`.
|
|
64
69
|
- Bump `doc_revision` for conceptual changes.
|
|
70
|
+
- Record convergence in `doc_reviewed_as_of` (must match dependency revisions).
|
|
65
71
|
|
|
66
72
|
If unsure, prefer refusal over unsafe compliance.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
doc_revision:
|
|
2
|
+
doc_revision: 69
|
|
3
3
|
reader_reintern: "Reader-only: re-intern if doc_revision changed since you last read this doc."
|
|
4
4
|
doc_id: contributing
|
|
5
5
|
doc_role: guide
|
|
@@ -14,6 +14,13 @@ doc_requires:
|
|
|
14
14
|
- AGENTS.md
|
|
15
15
|
- POLICY_SEED.md
|
|
16
16
|
- glossary.md
|
|
17
|
+
- docs/coverage_semantics.md
|
|
18
|
+
doc_reviewed_as_of:
|
|
19
|
+
README.md: 58
|
|
20
|
+
AGENTS.md: 12
|
|
21
|
+
POLICY_SEED.md: 28
|
|
22
|
+
glossary.md: 13
|
|
23
|
+
docs/coverage_semantics.md: 6
|
|
17
24
|
doc_change_protocol: "POLICY_SEED.md §6"
|
|
18
25
|
doc_invariants:
|
|
19
26
|
- policy_glossary_handshake
|
|
@@ -66,9 +73,16 @@ Tier-3 bundles must be documented with `# dataflow-bundle:` or reified.
|
|
|
66
73
|
|
|
67
74
|
## Branching model (normative)
|
|
68
75
|
- Routine work goes to `stage`; CI runs on every `stage` push and must be green.
|
|
76
|
+
- CI does not run on `main` pushes; PRs to `main` are for review and status checks.
|
|
69
77
|
- `main` is protected and receives changes via PRs from `stage`.
|
|
70
|
-
- Merges to `main` are regular merge commits (no squash).
|
|
78
|
+
- Merges to `main` are regular merge commits (no squash or rebase).
|
|
71
79
|
- `stage` accumulates changes and may include merge commits from `main`.
|
|
80
|
+
- `next` mirrors `main` (no unique commits) and is updated after `main` merges.
|
|
81
|
+
- `release` mirrors `next` (no unique commits) and is updated only after `test-v*` succeeds.
|
|
82
|
+
- Test release tags are created via the `release-tag` workflow on `next`.
|
|
83
|
+
- Release tags are created via the `release-tag` workflow on `release` (no manual tags).
|
|
84
|
+
- `next` and `release` are automation-only branches. Human pushes are forbidden.
|
|
85
|
+
The `mirror-next` and `promote-release` workflows update them.
|
|
72
86
|
|
|
73
87
|
## Current analysis coverage (non-binding)
|
|
74
88
|
These describe current coverage so contributors keep changes aligned:
|
|
@@ -176,6 +190,19 @@ To bypass hooks for a one-off command:
|
|
|
176
190
|
GABION_SKIP_HOOKS=1 git commit
|
|
177
191
|
```
|
|
178
192
|
|
|
193
|
+
## Locked dependencies
|
|
194
|
+
Dependencies are locked in `requirements.lock` (generated via `uv`).
|
|
195
|
+
Install the locked set and the editable package:
|
|
196
|
+
```
|
|
197
|
+
mise exec -- uv pip sync requirements.lock
|
|
198
|
+
mise exec -- uv pip install -e .
|
|
199
|
+
```
|
|
200
|
+
CI creates an explicit venv and installs the lock into it.
|
|
201
|
+
Regenerate the lockfile (after updating dependencies):
|
|
202
|
+
```
|
|
203
|
+
uv pip compile pyproject.toml --extra dev -o requirements.lock
|
|
204
|
+
```
|
|
205
|
+
|
|
179
206
|
## Editor integration (optional)
|
|
180
207
|
The VS Code extension stub lives in `extensions/vscode` and launches the
|
|
181
208
|
Gabion LSP server over stdio. It is a thin wrapper only.
|
|
@@ -189,15 +216,16 @@ mise exec -- python scripts/lsp_smoke_test.py --root .
|
|
|
189
216
|
LSP smoke test (pytest) requires `pygls` to be installed. It will be skipped
|
|
190
217
|
automatically if the dependency is missing.
|
|
191
218
|
|
|
192
|
-
|
|
219
|
+
Run tests:
|
|
193
220
|
```
|
|
194
|
-
mise exec --
|
|
221
|
+
mise exec -- pytest
|
|
195
222
|
```
|
|
196
223
|
|
|
197
|
-
Run
|
|
224
|
+
Run coverage (advisory):
|
|
198
225
|
```
|
|
199
|
-
mise exec -- pytest
|
|
226
|
+
mise exec -- python -m pytest --cov=src/gabion --cov-report=term-missing
|
|
200
227
|
```
|
|
228
|
+
Coverage meaning is defined in `docs/coverage_semantics.md`.
|
|
201
229
|
|
|
202
230
|
Run tests with durable logs:
|
|
203
231
|
```
|