calcifier 0.1.1__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.
- calcifier-0.1.1/.claude-plugin/marketplace.json +15 -0
- calcifier-0.1.1/.github/dependabot.yml +21 -0
- calcifier-0.1.1/.github/workflows/actionlint.yml +38 -0
- calcifier-0.1.1/.github/workflows/ci.yml +181 -0
- calcifier-0.1.1/.github/workflows/mutation.yml +116 -0
- calcifier-0.1.1/.github/workflows/publish.yml +127 -0
- calcifier-0.1.1/.github/workflows/zizmor.yml +29 -0
- calcifier-0.1.1/.gitignore +27 -0
- calcifier-0.1.1/AGENTS.md +53 -0
- calcifier-0.1.1/CHANGELOG.md +77 -0
- calcifier-0.1.1/CODE_OF_CONDUCT.md +73 -0
- calcifier-0.1.1/CONTRIBUTING.md +147 -0
- calcifier-0.1.1/LICENSE +21 -0
- calcifier-0.1.1/Makefile +95 -0
- calcifier-0.1.1/PKG-INFO +127 -0
- calcifier-0.1.1/README.md +99 -0
- calcifier-0.1.1/SECURITY.md +51 -0
- calcifier-0.1.1/SUPPORT.md +14 -0
- calcifier-0.1.1/docs/architecture.md +215 -0
- calcifier-0.1.1/docs/providers.md +127 -0
- calcifier-0.1.1/docs/recipes.md +202 -0
- calcifier-0.1.1/docs/trace-schema.json +768 -0
- calcifier-0.1.1/docs/usage.md +192 -0
- calcifier-0.1.1/plugins/calcifier/.claude-plugin/plugin.json +13 -0
- calcifier-0.1.1/plugins/calcifier/skills/calcifier/.calcifier/recipe.py +33 -0
- calcifier-0.1.1/plugins/calcifier/skills/calcifier/SKILL.md +43 -0
- calcifier-0.1.1/plugins/calcifier/skills/debug/.calcifier/recipe.py +38 -0
- calcifier-0.1.1/plugins/calcifier/skills/debug/SKILL.md +41 -0
- calcifier-0.1.1/plugins/calcifier/skills/exec/.calcifier/recipe.py +40 -0
- calcifier-0.1.1/plugins/calcifier/skills/exec/SKILL.md +46 -0
- calcifier-0.1.1/plugins/calcifier/skills/update/.calcifier/recipe.py +33 -0
- calcifier-0.1.1/plugins/calcifier/skills/update/SKILL.md +36 -0
- calcifier-0.1.1/pyproject.toml +141 -0
- calcifier-0.1.1/scripts/acceptance.py +687 -0
- calcifier-0.1.1/scripts/acceptance.sh +5 -0
- calcifier-0.1.1/scripts/compiler_replay.py +293 -0
- calcifier-0.1.1/scripts/mutation_shards.py +59 -0
- calcifier-0.1.1/scripts/mutation_threshold.py +111 -0
- calcifier-0.1.1/scripts/mutation_weights.json +327 -0
- calcifier-0.1.1/scripts/verify_artifacts.py +173 -0
- calcifier-0.1.1/src/calcifier/__init__.py +73 -0
- calcifier-0.1.1/src/calcifier/agent_config.py +263 -0
- calcifier-0.1.1/src/calcifier/agent_events.py +450 -0
- calcifier-0.1.1/src/calcifier/agent_providers.py +342 -0
- calcifier-0.1.1/src/calcifier/agents.py +227 -0
- calcifier-0.1.1/src/calcifier/artifact.py +313 -0
- calcifier-0.1.1/src/calcifier/atomic_io.py +31 -0
- calcifier-0.1.1/src/calcifier/baseline.py +159 -0
- calcifier-0.1.1/src/calcifier/budget.py +63 -0
- calcifier-0.1.1/src/calcifier/calcify.py +51 -0
- calcifier-0.1.1/src/calcifier/catalog.py +139 -0
- calcifier-0.1.1/src/calcifier/cli.py +787 -0
- calcifier-0.1.1/src/calcifier/cli_options.py +108 -0
- calcifier-0.1.1/src/calcifier/clock.py +79 -0
- calcifier-0.1.1/src/calcifier/compiler_activity.py +108 -0
- calcifier-0.1.1/src/calcifier/compiler_resources.py +98 -0
- calcifier-0.1.1/src/calcifier/composition.py +347 -0
- calcifier-0.1.1/src/calcifier/diagnostics.py +172 -0
- calcifier-0.1.1/src/calcifier/dry_run.py +500 -0
- calcifier-0.1.1/src/calcifier/effect_methods.py +39 -0
- calcifier-0.1.1/src/calcifier/exceptions.py +28 -0
- calcifier-0.1.1/src/calcifier/filesystem_contract.py +88 -0
- calcifier-0.1.1/src/calcifier/gate.py +996 -0
- calcifier-0.1.1/src/calcifier/graph.py +112 -0
- calcifier-0.1.1/src/calcifier/graph_build.py +241 -0
- calcifier-0.1.1/src/calcifier/graph_edges.py +34 -0
- calcifier-0.1.1/src/calcifier/hashing.py +9 -0
- calcifier-0.1.1/src/calcifier/instruction_context.py +197 -0
- calcifier-0.1.1/src/calcifier/json_config.py +16 -0
- calcifier-0.1.1/src/calcifier/metadata.py +235 -0
- calcifier-0.1.1/src/calcifier/mutations.py +318 -0
- calcifier-0.1.1/src/calcifier/native_events.py +299 -0
- calcifier-0.1.1/src/calcifier/output_annotations.py +149 -0
- calcifier-0.1.1/src/calcifier/outputs.py +550 -0
- calcifier-0.1.1/src/calcifier/parallel_contract.py +61 -0
- calcifier-0.1.1/src/calcifier/path_syntax.py +30 -0
- calcifier-0.1.1/src/calcifier/portable.py +373 -0
- calcifier-0.1.1/src/calcifier/prepared_context.py +82 -0
- calcifier-0.1.1/src/calcifier/prompts.py +370 -0
- calcifier-0.1.1/src/calcifier/py.typed +0 -0
- calcifier-0.1.1/src/calcifier/recipe.py +1217 -0
- calcifier-0.1.1/src/calcifier/recipe_ast.py +577 -0
- calcifier-0.1.1/src/calcifier/recipe_draft.py +218 -0
- calcifier-0.1.1/src/calcifier/registry.py +83 -0
- calcifier-0.1.1/src/calcifier/repair.py +534 -0
- calcifier-0.1.1/src/calcifier/run_result.py +119 -0
- calcifier-0.1.1/src/calcifier/runtime_conformance.py +135 -0
- calcifier-0.1.1/src/calcifier/side_effects.py +91 -0
- calcifier-0.1.1/src/calcifier/skill_frontmatter.py +89 -0
- calcifier-0.1.1/src/calcifier/skill_package.py +271 -0
- calcifier-0.1.1/src/calcifier/source_quality.py +392 -0
- calcifier-0.1.1/src/calcifier/subprocesses.py +407 -0
- calcifier-0.1.1/src/calcifier/taint.py +603 -0
- calcifier-0.1.1/src/calcifier/tools.py +456 -0
- calcifier-0.1.1/src/calcifier/trace.py +532 -0
- calcifier-0.1.1/src/calcifier/trace_export.py +203 -0
- calcifier-0.1.1/src/calcifier/trace_profile.py +83 -0
- calcifier-0.1.1/src/calcifier/trust.py +483 -0
- calcifier-0.1.1/src/calcifier/type_check.py +105 -0
- calcifier-0.1.1/src/calcifier/update.py +65 -0
- calcifier-0.1.1/src/calcifier/usage.py +61 -0
- calcifier-0.1.1/src/calcifier/validation.py +29 -0
- calcifier-0.1.1/src/calcifier/windows_job.py +202 -0
- calcifier-0.1.1/tests/__init__.py +0 -0
- calcifier-0.1.1/tests/conftest.py +202 -0
- calcifier-0.1.1/tests/corpus/changelog-entry/SKILL.md +13 -0
- calcifier-0.1.1/tests/corpus/changelog-entry/case.json +8 -0
- calcifier-0.1.1/tests/corpus/changelog-entry/draft.py +39 -0
- calcifier-0.1.1/tests/corpus/notes-summary/SKILL.md +13 -0
- calcifier-0.1.1/tests/corpus/notes-summary/case.json +3 -0
- calcifier-0.1.1/tests/corpus/notes-summary/draft.py +31 -0
- calcifier-0.1.1/tests/corpus/per-item-records/SKILL.md +13 -0
- calcifier-0.1.1/tests/corpus/per-item-records/case.json +25 -0
- calcifier-0.1.1/tests/corpus/per-item-records/draft.py +52 -0
- calcifier-0.1.1/tests/corpus/plugin-calcifier/SKILL.md +43 -0
- calcifier-0.1.1/tests/corpus/plugin-calcifier/case.json +3 -0
- calcifier-0.1.1/tests/corpus/plugin-calcifier/draft.py +24 -0
- calcifier-0.1.1/tests/corpus/plugin-debug/SKILL.md +41 -0
- calcifier-0.1.1/tests/corpus/plugin-debug/case.json +3 -0
- calcifier-0.1.1/tests/corpus/plugin-debug/draft.py +29 -0
- calcifier-0.1.1/tests/corpus/plugin-exec/SKILL.md +46 -0
- calcifier-0.1.1/tests/corpus/plugin-exec/case.json +3 -0
- calcifier-0.1.1/tests/corpus/plugin-exec/draft.py +31 -0
- calcifier-0.1.1/tests/corpus/plugin-update/SKILL.md +38 -0
- calcifier-0.1.1/tests/corpus/plugin-update/case.json +3 -0
- calcifier-0.1.1/tests/corpus/plugin-update/draft.py +24 -0
- calcifier-0.1.1/tests/corpus/release-digest/SKILL.md +13 -0
- calcifier-0.1.1/tests/corpus/release-digest/case.json +4 -0
- calcifier-0.1.1/tests/corpus/release-digest/children/release-notes/SKILL.md +12 -0
- calcifier-0.1.1/tests/corpus/release-digest/children/release-notes/case.json +3 -0
- calcifier-0.1.1/tests/corpus/release-digest/children/release-notes/draft.py +22 -0
- calcifier-0.1.1/tests/corpus/release-digest/draft.py +40 -0
- calcifier-0.1.1/tests/corpus/style-review/SKILL.md +19 -0
- calcifier-0.1.1/tests/corpus/style-review/case.json +3 -0
- calcifier-0.1.1/tests/corpus/style-review/draft.py +41 -0
- calcifier-0.1.1/tests/corpus/style-review/references/examples.md +4 -0
- calcifier-0.1.1/tests/corpus/style-review/references/style-guide.md +5 -0
- calcifier-0.1.1/tests/corpus/text-search/SKILL.md +14 -0
- calcifier-0.1.1/tests/corpus/text-search/case.json +3 -0
- calcifier-0.1.1/tests/corpus/text-search/draft.py +38 -0
- calcifier-0.1.1/tests/fixtures/sequencehash-sha256.json +56 -0
- calcifier-0.1.1/tests/fixtures/trivial_recipe.py +33 -0
- calcifier-0.1.1/tests/mutation_runner.py +228 -0
- calcifier-0.1.1/tests/mutation_sources.py +154 -0
- calcifier-0.1.1/tests/mutation_worker.py +34 -0
- calcifier-0.1.1/tests/support/SKILL.md +3 -0
- calcifier-0.1.1/tests/support/__init__.py +1 -0
- calcifier-0.1.1/tests/support/agents.py +55 -0
- calcifier-0.1.1/tests/support/ast.py +15 -0
- calcifier-0.1.1/tests/support/compiler.py +125 -0
- calcifier-0.1.1/tests/support/compiler_cases.py +149 -0
- calcifier-0.1.1/tests/support/recipes.py +158 -0
- calcifier-0.1.1/tests/support/skill_source.py +3 -0
- calcifier-0.1.1/tests/support/trust.py +26 -0
- calcifier-0.1.1/tests/test_acceptance_runner.py +697 -0
- calcifier-0.1.1/tests/test_agent_context_delivery.py +95 -0
- calcifier-0.1.1/tests/test_agent_timeout_budget.py +66 -0
- calcifier-0.1.1/tests/test_agents.py +1389 -0
- calcifier-0.1.1/tests/test_artifact.py +368 -0
- calcifier-0.1.1/tests/test_baseline.py +456 -0
- calcifier-0.1.1/tests/test_budget.py +195 -0
- calcifier-0.1.1/tests/test_catalog.py +259 -0
- calcifier-0.1.1/tests/test_cli.py +1338 -0
- calcifier-0.1.1/tests/test_cli_agent_budget.py +66 -0
- calcifier-0.1.1/tests/test_cli_options.py +39 -0
- calcifier-0.1.1/tests/test_cli_runtime_boundaries.py +270 -0
- calcifier-0.1.1/tests/test_clock.py +144 -0
- calcifier-0.1.1/tests/test_command_preflight.py +171 -0
- calcifier-0.1.1/tests/test_command_results.py +354 -0
- calcifier-0.1.1/tests/test_compilation_limits.py +177 -0
- calcifier-0.1.1/tests/test_compiler_activity.py +86 -0
- calcifier-0.1.1/tests/test_compiler_artifact_boundaries.py +125 -0
- calcifier-0.1.1/tests/test_compiler_context_boundaries.py +109 -0
- calcifier-0.1.1/tests/test_compiler_deadline.py +254 -0
- calcifier-0.1.1/tests/test_compiler_prompts.py +74 -0
- calcifier-0.1.1/tests/test_compiler_replay.py +73 -0
- calcifier-0.1.1/tests/test_compiler_resources.py +344 -0
- calcifier-0.1.1/tests/test_compiler_workflows.py +278 -0
- calcifier-0.1.1/tests/test_composition.py +1046 -0
- calcifier-0.1.1/tests/test_context_token_payloads.py +122 -0
- calcifier-0.1.1/tests/test_corpus.py +144 -0
- calcifier-0.1.1/tests/test_decorator_aliases.py +106 -0
- calcifier-0.1.1/tests/test_dry_run.py +763 -0
- calcifier-0.1.1/tests/test_dry_run_artifacts.py +114 -0
- calcifier-0.1.1/tests/test_dry_run_host_schemas.py +72 -0
- calcifier-0.1.1/tests/test_dry_run_provenance.py +99 -0
- calcifier-0.1.1/tests/test_effect_constructor_aliases.py +72 -0
- calcifier-0.1.1/tests/test_effect_methods.py +27 -0
- calcifier-0.1.1/tests/test_encoded_required_fields.py +138 -0
- calcifier-0.1.1/tests/test_gate.py +796 -0
- calcifier-0.1.1/tests/test_gate_source.py +1243 -0
- calcifier-0.1.1/tests/test_graph_build.py +226 -0
- calcifier-0.1.1/tests/test_hashing.py +16 -0
- calcifier-0.1.1/tests/test_host_results.py +200 -0
- calcifier-0.1.1/tests/test_mapping_transport.py +141 -0
- calcifier-0.1.1/tests/test_metadata.py +42 -0
- calcifier-0.1.1/tests/test_module_alias_preflight.py +62 -0
- calcifier-0.1.1/tests/test_mutation_gate.py +189 -0
- calcifier-0.1.1/tests/test_mutation_runner.py +520 -0
- calcifier-0.1.1/tests/test_mutation_sources.py +248 -0
- calcifier-0.1.1/tests/test_mutation_survivors.py +98 -0
- calcifier-0.1.1/tests/test_mutation_threshold.py +131 -0
- calcifier-0.1.1/tests/test_mutations.py +670 -0
- calcifier-0.1.1/tests/test_native_compilation.py +95 -0
- calcifier-0.1.1/tests/test_native_event_stream.py +461 -0
- calcifier-0.1.1/tests/test_native_schema_delivery.py +155 -0
- calcifier-0.1.1/tests/test_offline.py +47 -0
- calcifier-0.1.1/tests/test_output_type_aliases.py +100 -0
- calcifier-0.1.1/tests/test_outputs.py +497 -0
- calcifier-0.1.1/tests/test_outputs_answers.py +75 -0
- calcifier-0.1.1/tests/test_owner_failure_classes.py +213 -0
- calcifier-0.1.1/tests/test_parallel_command_policy.py +40 -0
- calcifier-0.1.1/tests/test_parallel_results.py +204 -0
- calcifier-0.1.1/tests/test_plain_helpers.py +109 -0
- calcifier-0.1.1/tests/test_plugin_dogfood.py +110 -0
- calcifier-0.1.1/tests/test_portable.py +753 -0
- calcifier-0.1.1/tests/test_prepared_context.py +101 -0
- calcifier-0.1.1/tests/test_prepared_workspace.py +74 -0
- calcifier-0.1.1/tests/test_prompts.py +277 -0
- calcifier-0.1.1/tests/test_public_recipe_surface.py +63 -0
- calcifier-0.1.1/tests/test_recipe.py +949 -0
- calcifier-0.1.1/tests/test_recipe_answers.py +406 -0
- calcifier-0.1.1/tests/test_recipe_body_effects.py +203 -0
- calcifier-0.1.1/tests/test_recipe_draft.py +200 -0
- calcifier-0.1.1/tests/test_repair.py +354 -0
- calcifier-0.1.1/tests/test_repair_indentation.py +103 -0
- calcifier-0.1.1/tests/test_repair_rendering.py +240 -0
- calcifier-0.1.1/tests/test_repair_targeting.py +185 -0
- calcifier-0.1.1/tests/test_report_tables.py +118 -0
- calcifier-0.1.1/tests/test_resource_sources.py +224 -0
- calcifier-0.1.1/tests/test_review_acceptance.py +137 -0
- calcifier-0.1.1/tests/test_runtime_conformance.py +188 -0
- calcifier-0.1.1/tests/test_runtime_conformance_acceptance.py +377 -0
- calcifier-0.1.1/tests/test_runtime_regressions.py +329 -0
- calcifier-0.1.1/tests/test_schema_keyword_fields.py +62 -0
- calcifier-0.1.1/tests/test_side_effects.py +129 -0
- calcifier-0.1.1/tests/test_side_effects_answers.py +266 -0
- calcifier-0.1.1/tests/test_skill_frontmatter.py +64 -0
- calcifier-0.1.1/tests/test_skill_package.py +564 -0
- calcifier-0.1.1/tests/test_skill_package_answers.py +45 -0
- calcifier-0.1.1/tests/test_source_construction.py +176 -0
- calcifier-0.1.1/tests/test_source_quality.py +446 -0
- calcifier-0.1.1/tests/test_source_repair_boundaries.py +62 -0
- calcifier-0.1.1/tests/test_static_path_and_call_boundaries.py +89 -0
- calcifier-0.1.1/tests/test_step.py +365 -0
- calcifier-0.1.1/tests/test_structured_output_roots.py +95 -0
- calcifier-0.1.1/tests/test_submodule_tool_preflight.py +69 -0
- calcifier-0.1.1/tests/test_subprocesses.py +354 -0
- calcifier-0.1.1/tests/test_subprocesses_answers.py +51 -0
- calcifier-0.1.1/tests/test_taint.py +1110 -0
- calcifier-0.1.1/tests/test_taint_artifacts.py +59 -0
- calcifier-0.1.1/tests/test_thin_scaffolding.py +309 -0
- calcifier-0.1.1/tests/test_tools.py +399 -0
- calcifier-0.1.1/tests/test_tools_answers.py +184 -0
- calcifier-0.1.1/tests/test_trace_accounting_boundaries.py +66 -0
- calcifier-0.1.1/tests/test_trace_export.py +537 -0
- calcifier-0.1.1/tests/test_trust.py +494 -0
- calcifier-0.1.1/tests/test_trust_answers.py +290 -0
- calcifier-0.1.1/tests/test_type_check.py +329 -0
- calcifier-0.1.1/tests/test_unused_capabilities.py +99 -0
- calcifier-0.1.1/tests/test_update.py +206 -0
- calcifier-0.1.1/tests/test_usage_accounting.py +234 -0
- calcifier-0.1.1/tests/test_validation.py +48 -0
- calcifier-0.1.1/tests/test_verify_artifacts.py +76 -0
- calcifier-0.1.1/tests/test_wall_budget_cli.py +132 -0
- calcifier-0.1.1/tests/test_windows_job.py +273 -0
- calcifier-0.1.1/tests/test_writable_agents.py +327 -0
- calcifier-0.1.1/uv.lock +612 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "calcifier",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Trail of Bits",
|
|
5
|
+
"url": "https://www.trailofbits.com"
|
|
6
|
+
},
|
|
7
|
+
"description": "Typed, executable Python recipes for Claude and Codex skills.",
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "calcifier",
|
|
11
|
+
"source": "./plugins/calcifier",
|
|
12
|
+
"description": "Calcify, execute, debug, and update typed agent recipes"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
cooldown:
|
|
8
|
+
default-days: 7
|
|
9
|
+
groups:
|
|
10
|
+
all:
|
|
11
|
+
patterns: ["*"]
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: github-actions
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
17
|
+
cooldown:
|
|
18
|
+
default-days: 7
|
|
19
|
+
groups:
|
|
20
|
+
all:
|
|
21
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Actionlint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
actionlint:
|
|
18
|
+
name: actionlint
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
|
|
25
|
+
- name: Install actionlint
|
|
26
|
+
run: |
|
|
27
|
+
set -euo pipefail
|
|
28
|
+
# Pinned to actionlint v1.7.12 release tarball.
|
|
29
|
+
ACTIONLINT_VERSION="1.7.12"
|
|
30
|
+
ACTIONLINT_SHA256="8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8"
|
|
31
|
+
curl -fsSL -o actionlint.tar.gz \
|
|
32
|
+
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
|
|
33
|
+
echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c -
|
|
34
|
+
tar -xzf actionlint.tar.gz actionlint
|
|
35
|
+
chmod +x actionlint
|
|
36
|
+
|
|
37
|
+
- name: Run actionlint
|
|
38
|
+
run: ./actionlint -color
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
PYTHONWARNDEFAULTENCODING: "1"
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
lint:
|
|
21
|
+
name: Lint
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
25
|
+
with:
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
|
|
28
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
29
|
+
|
|
30
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.13"
|
|
33
|
+
|
|
34
|
+
- run: uv sync --all-groups --locked
|
|
35
|
+
|
|
36
|
+
- run: make lockcheck lint portable
|
|
37
|
+
|
|
38
|
+
type-check:
|
|
39
|
+
name: Type check (ty)
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
|
+
with:
|
|
44
|
+
persist-credentials: false
|
|
45
|
+
|
|
46
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
47
|
+
|
|
48
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.13"
|
|
51
|
+
|
|
52
|
+
- run: uv sync --all-groups --locked
|
|
53
|
+
|
|
54
|
+
- run: make typecheck
|
|
55
|
+
|
|
56
|
+
test:
|
|
57
|
+
name: Test
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
strategy:
|
|
60
|
+
fail-fast: false
|
|
61
|
+
matrix:
|
|
62
|
+
# "Test (3.13)" and "Test (3.14)" are required status checks in the main
|
|
63
|
+
# branch ruleset; removing a version leaves its check pending forever.
|
|
64
|
+
python-version: ["3.13", "3.14"]
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
67
|
+
with:
|
|
68
|
+
persist-credentials: false
|
|
69
|
+
|
|
70
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
71
|
+
|
|
72
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
73
|
+
with:
|
|
74
|
+
python-version: ${{ matrix.python-version }}
|
|
75
|
+
|
|
76
|
+
- run: uv sync --all-groups --locked
|
|
77
|
+
|
|
78
|
+
- run: uv run pytest -q -n auto tests/
|
|
79
|
+
|
|
80
|
+
windows-test:
|
|
81
|
+
name: Windows test (3.13)
|
|
82
|
+
runs-on: windows-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
85
|
+
with:
|
|
86
|
+
persist-credentials: false
|
|
87
|
+
|
|
88
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
89
|
+
|
|
90
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
91
|
+
with:
|
|
92
|
+
python-version: "3.13"
|
|
93
|
+
|
|
94
|
+
- run: uv sync --all-groups --locked
|
|
95
|
+
|
|
96
|
+
- run: uv run pytest -q -n auto tests/
|
|
97
|
+
|
|
98
|
+
dep-audit:
|
|
99
|
+
name: Dependency audit (pip-audit)
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
steps:
|
|
102
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
103
|
+
with:
|
|
104
|
+
persist-credentials: false
|
|
105
|
+
|
|
106
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
107
|
+
|
|
108
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
109
|
+
with:
|
|
110
|
+
python-version: "3.13"
|
|
111
|
+
|
|
112
|
+
- name: Export locked requirements
|
|
113
|
+
run: |
|
|
114
|
+
uv export --frozen --all-groups --format requirements-txt \
|
|
115
|
+
--no-emit-project -o requirements-frozen.txt
|
|
116
|
+
|
|
117
|
+
- name: Run pip-audit against the lockfile export
|
|
118
|
+
run: uvx pip-audit -r requirements-frozen.txt --disable-pip --strict
|
|
119
|
+
|
|
120
|
+
coverage:
|
|
121
|
+
name: Coverage
|
|
122
|
+
runs-on: ubuntu-latest
|
|
123
|
+
steps:
|
|
124
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
125
|
+
with:
|
|
126
|
+
persist-credentials: false
|
|
127
|
+
|
|
128
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
129
|
+
|
|
130
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
131
|
+
with:
|
|
132
|
+
python-version: "3.13"
|
|
133
|
+
|
|
134
|
+
- run: uv sync --all-groups --locked
|
|
135
|
+
|
|
136
|
+
- run: uv run coverage run --branch -m pytest -q tests/
|
|
137
|
+
|
|
138
|
+
- name: Coverage report (gate)
|
|
139
|
+
run: uv run coverage report
|
|
140
|
+
|
|
141
|
+
- name: Coverage XML for upload
|
|
142
|
+
run: uv run coverage xml -o coverage.xml
|
|
143
|
+
|
|
144
|
+
- name: Upload coverage XML
|
|
145
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
146
|
+
with:
|
|
147
|
+
name: coverage-xml
|
|
148
|
+
path: coverage.xml
|
|
149
|
+
|
|
150
|
+
build:
|
|
151
|
+
name: Build sdist + wheel
|
|
152
|
+
runs-on: ubuntu-latest
|
|
153
|
+
steps:
|
|
154
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
155
|
+
with:
|
|
156
|
+
persist-credentials: false
|
|
157
|
+
|
|
158
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
159
|
+
|
|
160
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
161
|
+
with:
|
|
162
|
+
python-version: "3.13"
|
|
163
|
+
|
|
164
|
+
- name: Seed deliberately dirty workstation state
|
|
165
|
+
run: |
|
|
166
|
+
mkdir -p .claude .hypothesis .vivisect
|
|
167
|
+
touch .claude/release-leak .hypothesis/release-leak .vivisect/release-leak
|
|
168
|
+
|
|
169
|
+
- run: uv build
|
|
170
|
+
|
|
171
|
+
- name: Verify artifact contents and version surfaces
|
|
172
|
+
run: uv run python scripts/verify_artifacts.py dist/
|
|
173
|
+
|
|
174
|
+
- run: uvx twine check dist/*
|
|
175
|
+
|
|
176
|
+
- name: Smoke-import the wheel
|
|
177
|
+
run: |
|
|
178
|
+
python -m venv /tmp/wheel-check
|
|
179
|
+
/tmp/wheel-check/bin/pip install dist/*.whl
|
|
180
|
+
/tmp/wheel-check/bin/python -c "import calcifier; print(calcifier.__version__)"
|
|
181
|
+
/tmp/wheel-check/bin/calcifier --version
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
name: Mutation Testing
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
# Finish the costly report; keep only the newest pending commit in this group.
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
gremlins:
|
|
19
|
+
name: Mutation shard (${{ matrix.operator }}, ${{ matrix.index }})
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
include:
|
|
25
|
+
# Balance complete modules by observed per-operator mutant runtime.
|
|
26
|
+
# Boolean has the most work; comparison was a single multi-hour job.
|
|
27
|
+
- {operator: comparison, index: 0, count: 4}
|
|
28
|
+
- {operator: comparison, index: 1, count: 4}
|
|
29
|
+
- {operator: comparison, index: 2, count: 4}
|
|
30
|
+
- {operator: comparison, index: 3, count: 4}
|
|
31
|
+
- {operator: arithmetic, index: 0, count: 2}
|
|
32
|
+
- {operator: arithmetic, index: 1, count: 2}
|
|
33
|
+
- {operator: boolean, index: 0, count: 8}
|
|
34
|
+
- {operator: boolean, index: 1, count: 8}
|
|
35
|
+
- {operator: boolean, index: 2, count: 8}
|
|
36
|
+
- {operator: boolean, index: 3, count: 8}
|
|
37
|
+
- {operator: boolean, index: 4, count: 8}
|
|
38
|
+
- {operator: boolean, index: 5, count: 8}
|
|
39
|
+
- {operator: boolean, index: 6, count: 8}
|
|
40
|
+
- {operator: boolean, index: 7, count: 8}
|
|
41
|
+
- {operator: boundary, index: 0, count: 2}
|
|
42
|
+
- {operator: boundary, index: 1, count: 2}
|
|
43
|
+
- {operator: return, index: 0, count: 4}
|
|
44
|
+
- {operator: return, index: 1, count: 4}
|
|
45
|
+
- {operator: return, index: 2, count: 4}
|
|
46
|
+
- {operator: return, index: 3, count: 4}
|
|
47
|
+
env:
|
|
48
|
+
ANTHROPIC_API_KEY: ""
|
|
49
|
+
OPENAI_API_KEY: ""
|
|
50
|
+
GREMLIN_OPERATORS: ${{ matrix.operator }}
|
|
51
|
+
GREMLIN_CACHE: "1"
|
|
52
|
+
SHARD_INDEX: ${{ matrix.index }}
|
|
53
|
+
SHARD_COUNT: ${{ matrix.count }}
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
56
|
+
with:
|
|
57
|
+
persist-credentials: false
|
|
58
|
+
|
|
59
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
60
|
+
|
|
61
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
62
|
+
with:
|
|
63
|
+
python-version: "3.13"
|
|
64
|
+
|
|
65
|
+
# Reuse results only when the complete code and test inputs match. The
|
|
66
|
+
# plugin also hashes each target and its covering tests internally.
|
|
67
|
+
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
68
|
+
with:
|
|
69
|
+
path: .gremlins_cache
|
|
70
|
+
key: gremlins-${{ runner.os }}-py313-${{ matrix.operator }}-${{ matrix.index }}of${{ matrix.count }}-${{ hashFiles('uv.lock', 'pyproject.toml', 'Makefile', 'src/**', 'tests/**', 'plugins/**', 'scripts/mutation_shards.py', 'scripts/mutation_weights.json', '.github/workflows/mutation.yml') }}
|
|
71
|
+
|
|
72
|
+
- run: uv sync --all-groups --locked
|
|
73
|
+
|
|
74
|
+
- name: Mutate this operator's module partition
|
|
75
|
+
run: |
|
|
76
|
+
set -euo pipefail
|
|
77
|
+
MUTATION_RUN_TARGETS="$(python3 scripts/mutation_shards.py --operator "$GREMLIN_OPERATORS" --index "$SHARD_INDEX" --count "$SHARD_COUNT")"
|
|
78
|
+
export MUTATION_RUN_TARGETS
|
|
79
|
+
make mutate
|
|
80
|
+
test -s coverage/gremlins/gremlins.json
|
|
81
|
+
|
|
82
|
+
- name: Upload report
|
|
83
|
+
if: always() && hashFiles('coverage/gremlins/gremlins.json') != ''
|
|
84
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
85
|
+
with:
|
|
86
|
+
name: gremlins-report-${{ matrix.operator }}-${{ matrix.index }}
|
|
87
|
+
path: coverage/gremlins/
|
|
88
|
+
|
|
89
|
+
mutation-threshold:
|
|
90
|
+
name: Mutation Testing (pytest-gremlins)
|
|
91
|
+
if: always()
|
|
92
|
+
needs: gremlins
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
steps:
|
|
95
|
+
# A missing shard would silently shrink each module's denominator.
|
|
96
|
+
- name: Require every mutation shard
|
|
97
|
+
env:
|
|
98
|
+
SHARDS: ${{ needs.gremlins.result }}
|
|
99
|
+
run: test "$SHARDS" = success
|
|
100
|
+
|
|
101
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
102
|
+
with:
|
|
103
|
+
persist-credentials: false
|
|
104
|
+
|
|
105
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
106
|
+
with:
|
|
107
|
+
pattern: "gremlins-report-*"
|
|
108
|
+
path: coverage/shards
|
|
109
|
+
|
|
110
|
+
# Report-only until v0.1.0 ships: the per-module rate is printed but does not fail CI.
|
|
111
|
+
- name: Report the per-module kill rate
|
|
112
|
+
continue-on-error: true
|
|
113
|
+
run: |
|
|
114
|
+
set -euo pipefail
|
|
115
|
+
mapfile -d '' reports < <(find coverage/shards -name gremlins.json -print0)
|
|
116
|
+
python3 scripts/mutation_threshold.py "${reports[@]}" --min 90
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
# Releases are immutable and serialized through the GitHub release event;
|
|
8
|
+
# we still set workflow-level concurrency so a botched re-tag of the same
|
|
9
|
+
# release cannot race a previous publish run.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.event.release.tag_name }}
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
permissions: {}
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
name: Build
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
env:
|
|
23
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
24
|
+
steps:
|
|
25
|
+
- name: Verify release tag is a vX.Y.Z[-pre] version
|
|
26
|
+
run: |
|
|
27
|
+
set -euo pipefail
|
|
28
|
+
if ! printf '%s\n' "$RELEASE_TAG" \
|
|
29
|
+
| grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.?[0-9]+)?$'; then
|
|
30
|
+
echo "release tag '$RELEASE_TAG' does not match a publishable pattern" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
persist-credentials: false
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
ref: ${{ github.event.release.tag_name }}
|
|
39
|
+
|
|
40
|
+
- name: Verify annotated signed tag and main reachability
|
|
41
|
+
env:
|
|
42
|
+
GH_TOKEN: ${{ github.token }}
|
|
43
|
+
run: |
|
|
44
|
+
set -euo pipefail
|
|
45
|
+
git fetch --no-tags origin main
|
|
46
|
+
if [ "$(git cat-file -t "$RELEASE_TAG")" != tag ]; then
|
|
47
|
+
echo "$RELEASE_TAG is not an annotated tag" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
REF_JSON="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$RELEASE_TAG")"
|
|
51
|
+
TAG_OBJECT="$(printf '%s' "$REF_JSON" | jq -r '.object.sha')"
|
|
52
|
+
TAG_JSON="$(gh api "repos/$GITHUB_REPOSITORY/git/tags/$TAG_OBJECT")"
|
|
53
|
+
if [ "$(printf '%s' "$TAG_JSON" | jq -r '.verification.verified')" != true ]; then
|
|
54
|
+
printf '%s\n' "$TAG_JSON" | jq '.verification' >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
TAG_COMMIT="$(printf '%s' "$TAG_JSON" | jq -r '.object.sha')"
|
|
58
|
+
git merge-base --is-ancestor "$TAG_COMMIT" origin/main
|
|
59
|
+
test "$TAG_COMMIT" = "$(git rev-parse HEAD)"
|
|
60
|
+
|
|
61
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
62
|
+
with:
|
|
63
|
+
# Release artifacts must not depend on caches writable by lower-trust workflows.
|
|
64
|
+
enable-cache: false
|
|
65
|
+
|
|
66
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
67
|
+
with:
|
|
68
|
+
python-version: "3.13"
|
|
69
|
+
|
|
70
|
+
- run: uv sync --all-groups --locked
|
|
71
|
+
|
|
72
|
+
- name: Verify every source version surface
|
|
73
|
+
run: uv run python scripts/verify_artifacts.py --source-only --release-tag "$RELEASE_TAG"
|
|
74
|
+
|
|
75
|
+
- name: Re-run release verification suite
|
|
76
|
+
run: |
|
|
77
|
+
make verify
|
|
78
|
+
uv run coverage run -m pytest -q tests/
|
|
79
|
+
uv run coverage report
|
|
80
|
+
|
|
81
|
+
- name: Audit locked dependencies
|
|
82
|
+
run: |
|
|
83
|
+
uv export --frozen --all-groups --format requirements-txt \
|
|
84
|
+
--no-emit-project -o requirements-frozen.txt
|
|
85
|
+
uvx pip-audit -r requirements-frozen.txt --disable-pip --strict
|
|
86
|
+
|
|
87
|
+
- run: uv build
|
|
88
|
+
|
|
89
|
+
- name: Verify artifact contents and versions
|
|
90
|
+
run: uv run python scripts/verify_artifacts.py dist/
|
|
91
|
+
|
|
92
|
+
- run: uvx twine check dist/*
|
|
93
|
+
|
|
94
|
+
- name: Smoke-import the wheel
|
|
95
|
+
run: |
|
|
96
|
+
set -euo pipefail
|
|
97
|
+
python -m venv /tmp/wheel-check
|
|
98
|
+
/tmp/wheel-check/bin/pip install dist/*.whl
|
|
99
|
+
/tmp/wheel-check/bin/calcifier --version
|
|
100
|
+
|
|
101
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
102
|
+
with:
|
|
103
|
+
name: dist
|
|
104
|
+
path: dist/
|
|
105
|
+
|
|
106
|
+
publish:
|
|
107
|
+
name: Publish
|
|
108
|
+
needs: build
|
|
109
|
+
runs-on: ubuntu-latest
|
|
110
|
+
environment: pypi
|
|
111
|
+
permissions:
|
|
112
|
+
id-token: write # OIDC trusted publishing for pypa/gh-action-pypi-publish.
|
|
113
|
+
attestations: write # actions/attest-build-provenance signs the wheel + sdist.
|
|
114
|
+
contents: read # Read-only checkout of release metadata.
|
|
115
|
+
steps:
|
|
116
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
117
|
+
with:
|
|
118
|
+
name: dist
|
|
119
|
+
path: dist/
|
|
120
|
+
|
|
121
|
+
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
122
|
+
with:
|
|
123
|
+
subject-path: "dist/*"
|
|
124
|
+
|
|
125
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
126
|
+
with:
|
|
127
|
+
attestations: true
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Zizmor
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
actions: read # zizmor needs read access to introspect workflow metadata.
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
zizmor:
|
|
19
|
+
name: Workflow Security Audit
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
|
|
26
|
+
- uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
|
|
27
|
+
with:
|
|
28
|
+
version: "1.30.1"
|
|
29
|
+
advanced-security: false
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
.venv/
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.ruff_cache/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.calcifier-runtime/
|
|
10
|
+
coverage/
|
|
11
|
+
.gremlins_cache/
|
|
12
|
+
.claude/
|
|
13
|
+
.codex/
|
|
14
|
+
.remember/
|
|
15
|
+
.serena/
|
|
16
|
+
.uv-cache/
|
|
17
|
+
.vivisect/
|
|
18
|
+
|
|
19
|
+
# Coverage artifacts
|
|
20
|
+
.coverage
|
|
21
|
+
.coverage.*
|
|
22
|
+
coverage.xml
|
|
23
|
+
htmlcov/
|
|
24
|
+
|
|
25
|
+
# Generated benchmark reports
|
|
26
|
+
benchmarks/**/results/
|
|
27
|
+
benchmarks/**/*-results/
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Working on Calcifier
|
|
2
|
+
|
|
3
|
+
Calcifier turns a SKILL.md into a runnable Python workflow. Python handles
|
|
4
|
+
repeatable operations; agents handle understanding, interpretation, and uncertain
|
|
5
|
+
decisions. Preserve the skill's instructions, mandatory steps, and explicit
|
|
6
|
+
output requirements, including required fields and word counts.
|
|
7
|
+
Compiler behavior must stay independent of any particular skill or provider.
|
|
8
|
+
|
|
9
|
+
## Code organization
|
|
10
|
+
|
|
11
|
+
- `src/calcifier/` contains the compiler, runtime, and public package.
|
|
12
|
+
[docs/architecture.md](docs/architecture.md) maps their module boundaries.
|
|
13
|
+
- `tests/` contains offline regression tests and neutral skill fixtures;
|
|
14
|
+
shared fixtures belong in `tests/support/`.
|
|
15
|
+
- `scripts/` contains development tools, not runtime dependencies.
|
|
16
|
+
- `docs/` contains detailed usage and design notes. Keep the README focused on
|
|
17
|
+
what Calcifier does, why someone would use it, and where to start.
|
|
18
|
+
|
|
19
|
+
## Changes
|
|
20
|
+
|
|
21
|
+
- Prefer deleting duplication to adding abstractions. Use existing helpers and
|
|
22
|
+
module boundaries; avoid speculative frameworks and compatibility layers.
|
|
23
|
+
- Fix the general mechanism behind a failure. Do not add compiler rules, prompt
|
|
24
|
+
sentences, or tests tied to one skill's wording or domain.
|
|
25
|
+
- When a recipe uses an API naturally, prefer supporting that use over adding a
|
|
26
|
+
rejection rule. Before adding a check, see whether ty, the dry run, or repair
|
|
27
|
+
already catches the failure.
|
|
28
|
+
- Keep `calcifier.__all__` small. Generated recipes import only those names;
|
|
29
|
+
prefer extending an existing call over adding another public primitive.
|
|
30
|
+
- Preserve behavior and validation unless the task explicitly changes them.
|
|
31
|
+
Do not weaken an assertion or replace a failed result with an unverified one
|
|
32
|
+
to make tests pass. Compatibility work needs a supported API or format to serve.
|
|
33
|
+
- Keep rejection focused on behavioral defects: invalid code, certain runtime
|
|
34
|
+
failures, unsafe effects, and races. Formatting preferences and type precision
|
|
35
|
+
must not reject an otherwise runnable recipe.
|
|
36
|
+
- Always attempt the whole compiler dry run with stub agents and synthesized
|
|
37
|
+
inputs. Preserve its limits and report coverage gaps as unverified, never passed.
|
|
38
|
+
- Keep instruction handling direct; do not build fidelity proof machinery as a
|
|
39
|
+
substitute for compiling and running the recipe.
|
|
40
|
+
|
|
41
|
+
## Verification and workflow
|
|
42
|
+
|
|
43
|
+
- Run focused tests while editing, then `gmake verify`. This checks the lock,
|
|
44
|
+
Ruff, ty, portable plugin recipes, and the test suite. CI reports mutation
|
|
45
|
+
rates; do not run mutation testing locally.
|
|
46
|
+
- Tests must use stub providers and never call live Claude/Codex CLIs. Write
|
|
47
|
+
byte-exact fixtures with explicit encoding/newline settings; cover LF and CRLF
|
|
48
|
+
when preserving source or resource bytes.
|
|
49
|
+
- Live acceptance is owner-run. Do not inspect held-out fixtures, cohort lists,
|
|
50
|
+
or results, and do not run them yourself. Test the acceptance runner only with
|
|
51
|
+
neutral fixtures. Offline checks do not establish answer quality.
|
|
52
|
+
- Work in an isolated checkout, preserve the owner's local changes, keep
|
|
53
|
+
generated evidence outside Git, and use normal pushes.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.1.1 — 2026-10-14
|
|
4
|
+
|
|
5
|
+
Release metadata update for the first PyPI publication. The v0.1.0 GitHub
|
|
6
|
+
release used an unsigned lightweight tag and failed the signed-tag publishing
|
|
7
|
+
check. This release contains the features documented below for v0.1.0.
|
|
8
|
+
|
|
9
|
+
## v0.1.0 — 2026-10-14
|
|
10
|
+
|
|
11
|
+
First public release of Calcifier. Write Python workflows that combine
|
|
12
|
+
repeatable operations with agent reasoning, or compile them from existing
|
|
13
|
+
skills. Requires Python 3.13 or newer.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Python recipes.** Author workflows directly with `@recipe` and typed `@step`
|
|
18
|
+
functions, ordinary Python control flow, and async functions. Entry signatures
|
|
19
|
+
define typed CLI inputs. `fail()` aborts; `emit()` exposes named artifacts.
|
|
20
|
+
- **Skill compilation.** Generate a reviewable Python recipe from a `SKILL.md`
|
|
21
|
+
and packaged resources. Repeatable operations move into Python; reasoning
|
|
22
|
+
stays with agents. Generation, static checks, whole-recipe stub execution,
|
|
23
|
+
and repairs share a bounded call/time budget.
|
|
24
|
+
- **Runnable fallback.** Compilation starts from one agent session with the
|
|
25
|
+
intact skill. Failed optimization retains that baseline and reports
|
|
26
|
+
`baseline_retained`; `--require-compiled` preserves it but exits nonzero.
|
|
27
|
+
- **Typed agent responses.** Closed `@output_type` records enforce required
|
|
28
|
+
fields, value types, and constraints such as allowed values and word counts.
|
|
29
|
+
Invalid responses receive one parse retry. Codex receives schemas through its
|
|
30
|
+
native structured-output channel; the host validates full Python types.
|
|
31
|
+
- **Agent roles and budgets.** Configure Claude, Codex, or custom argv adapters
|
|
32
|
+
by semantic role. Steps, parallel workers, and children share call and wall
|
|
33
|
+
limits. `--max-agent-calls` bounds charged attempts, including parse retries,
|
|
34
|
+
without increasing declared limits.
|
|
35
|
+
`Budget.remaining_wall_seconds()` exposes the active run's effective time left.
|
|
36
|
+
Custom command adapters receive their effective timeout in the call contract.
|
|
37
|
+
- **Instruction delivery.** File-based recipes pin original instructions and
|
|
38
|
+
references. `prepare_context()` bundles complete tasks and prior results
|
|
39
|
+
without duplicating prompts or changing the project working directory.
|
|
40
|
+
- **Declared effects.** Contained, atomic report writes; artifact verification;
|
|
41
|
+
host argv commands; and soft/hard dry-run modes. `--output-dir` redirects a
|
|
42
|
+
declared root and protects existing files.
|
|
43
|
+
- **Typed command results.** `run_command(..., output=T)` validates successful
|
|
44
|
+
JSON stdout. Compiler dry runs execute read-only commands and synthesize
|
|
45
|
+
suppressed mutating results, reporting unavailable inputs as unverified.
|
|
46
|
+
- **Parallel checkpoints.** Serial `on_result` callbacks checkpoint completed
|
|
47
|
+
workers; `reuse_existing=True` adopts byte-identical artifacts for updates.
|
|
48
|
+
- **Resources and composition.** Verified resource snapshots, pinned child
|
|
49
|
+
recipes, shared budgets/output roots, and dependency-ordered graph builds
|
|
50
|
+
with closed catalogs.
|
|
51
|
+
- **Diagnostics and traces.** Compiler telemetry and incremental versioned run
|
|
52
|
+
traces record attempts, artifacts, effects, timing, budgets, and observed
|
|
53
|
+
usage. Missing usage remains unknown. `profile` summarizes a trace.
|
|
54
|
+
- **CLI and plugin.** Compile, execute, debug, update-by-diff, portable lint,
|
|
55
|
+
graph builds, and profiling; four Claude Code plugin skills with recipes.
|
|
56
|
+
|
|
57
|
+
### Security
|
|
58
|
+
|
|
59
|
+
- **Trust and integrity.** Execution requires consent for exact recipe bytes,
|
|
60
|
+
resources, and child pins. Compilation does not grant trust; adjacent trust
|
|
61
|
+
files have no authority. Recipes execute Python with host permissions; review
|
|
62
|
+
the source and dependencies before granting trust.
|
|
63
|
+
- **Behavioral checks.** Source checks reject certain runtime failures, unsafe
|
|
64
|
+
effects, model-controlled paths/commands, and races. Style and type precision
|
|
65
|
+
do not reject runnable candidates. Stub execution reports coverage gaps
|
|
66
|
+
without promoting them to passes.
|
|
67
|
+
- **Provider boundaries.** Host agents use explicit filesystem contracts and
|
|
68
|
+
clean settings. Subprocesses run without a shell under time/output limits.
|
|
69
|
+
- **Strict records and redaction.** Malformed trace/trust data fails closed.
|
|
70
|
+
Secret-like field names are redacted; free text still needs review.
|
|
71
|
+
- **Release provenance.** A signed-tag release workflow checks source and
|
|
72
|
+
artifact versions, uses PyPI trusted publishing and build attestations, and
|
|
73
|
+
builds without workflow caches.
|
|
74
|
+
|
|
75
|
+
See [usage](docs/usage.md), [architecture](docs/architecture.md), and
|
|
76
|
+
[providers](docs/providers.md) for contracts and limits. Compilation and offline
|
|
77
|
+
checks do not establish answer quality, instruction fidelity, or faster execution.
|