docs(kickoff): python-delivery-v0 umbrella — consumer install lane for the Python backends (S1-S3) - #967
Merged
Merged
Conversation
…r the Python backends, S1-S3 Kickoff for the python-delivery-v0 umbrella: './setup python' delivers pre-rendered astgrep/ruff enforcement into a consumer Python project (Model A commit-time pre-render + byte-drift gate), consumer CI template, post-install firing proof. Doc-only; Phase -1 cold-review passed (1 BLOCKER + 2 MAJOR fixed in one REVISE round, CONFIRMED-GO).
artyhoo
added a commit
that referenced
this pull request
Jul 11, 2026
…yte-drift gate, pure-bash delivery layer (python-delivery-v0) (#991) * docs(orchestrator): python-delivery-v0 meta-launch kickoff (launch-table + stage gates) Generated by /pipeline python-delivery-v0 (plan-currency: kickoff on staging #967, no in-flight S1, umbrella open). Orchestration record for the S1-S3 dispatch. Prior-art: skipped — orchestration bookkeeping doc, no new capability * feat(python-starter): curated Python starter ConventionNode[] set (S1 Task 3) Adds packages/core/python-starter/starter-nodes.ts — a curated Python starter node set authored in the frozen neutral IR (ir/types.ts, no field added) and rendered through the existing ADOPTED backends: renderAstgrep (#212, syntax-class default) and renderRuff (#215, TID251/TID253 fast-path). Colocated vitest unit tests (RED-first) assert: grammar-gate pass, getff-* id namespacing (probe-proven: duplicate ids = ast-grep exit 8), render-through-both-backends without error, the probe-proven firing shape, and the datetime caveat — the rendered YAML covers BOTH `datetime.now()` and `datetime.datetime.now()` via two literal-pattern nodes (a single pattern cannot match both; a `$MOD.now()` metavariable over-fires on `foo.now()` — live-verified against @ast-grep/cli@0.44.1). Set content (all severity error): ban datetime.now()/ datetime.datetime.now() calls (flagship P5), ban eval()/os.system() calls (bandit ADOPT-VOCABULARY; ruff refuses FF7001 — ast-grep catch-all), ban datetime.datetime.utcnow (TID251), ban module-level import tensorflow (TID253). SSOT row 217 appended to docs/meta-factory/prior-art-evaluations.md in this same commit (register tail verified: last row was 215; 216 is reserved for the delivery-layer task). vitest.config.ts registers the new python-starter/ include glob. Verified: python-starter 12/12, test:backends 154/154, test:principles 303/303, tsc --noEmit clean. Prior-art: prior-art-evaluations.md#217 (curated Python starter node set — BUILD own content in the neutral IR; ruff has no canonical "recommended" starter preset, bandit's catalog is engine-coupled with no neutral-IR export, Factory plugin #4 is JS/ESLint-coupled — ADOPT-VOCABULARY the ban semantics, author the set ourselves). * feat(python-delivery): commit-time render script + pre-rendered templates + byte-drift gate (S1 T4) Render the curated Python starter node set (packages/core/python-starter/starter-nodes.ts, #217) through the pure ADOPTED backends into static shipped templates under packages/core/templates/python/ (Model A). The renderers stay pure; all fs writes live in packages/core/python-starter/render-python-templates.ts (planPythonTemplates() is pure and is what the drift gate imports). Single-owner lane per rule (coordinator Decision #5), partitioned by node kind — a rule ships in exactly ONE lane so a consumer never gets a duplicate report: - ast-grep lane (call-kind): getff-no-datetime-now, getff-no-datetime-datetime-now, getff-no-eval, getff-no-os-system — one single-doc YAML file per rule under .getff/astgrep-rules/ (idiomatic ast-grep layout; a multi-doc stream fails the repo's own single-document pre-commit yaml.safe_load gate — empirically verified). - ruff lane (attribute/import-kind): getff-no-utcnow (TID251), getff-no-tensorflow-module-import (TID253) — one ruff.toml for the whole lane. Our own sgconfig.yml template (Decision #4, no `ast-grep new` shellout) references the rules dir from the consumer's perspective (ruleDirs: [.getff/astgrep-rules]). Every generated file carries a framework-generated header comment. Byte-drift gate: packages/core/backends/python-templates-drift.test.ts asserts committed templates == fresh render, byte-for-byte, at the pre-push channel (test:backends / hooks/pre-push.ts §5c). Idempotent: re-running the render script produces zero diff. Live-fired end-to-end against the pinned @ast-grep/cli@0.44.1 + ruff==0.15.21 on the exact consumer tree layout (both lanes fire; no rule double-reports). Templates land under a NEW packages/core/templates/python/ dir NOT in install.sh's enumerated copy-list — no install-fingerprint / shipped-doc / principle-test surface is touched. Prior-art: prior-art-evaluations.md#212 (ast-grep render backend, ADOPT) and prior-art-evaluations.md#215 (ruff fast-path render backend, ADOPT) — this commit renders the #217 curated node set through the already-ADOPTED backends; no new render target, the emission verdicts stand. * feat(python-delivery): pure-bash delivery layer + augment-first collision policy + tmp-dir tests (S1 T5) setup.d/45-python.sh ships the pre-rendered Python lint bundle (ast-grep rules + sgconfig.yml + ruff config, S1 Task 4) into a consumer Python repo with an augment-first collision policy — merge into what the consumer authored, never silently clobber. INERT on the npm flow (gated on GETFF_TOOLCHAIN=python; S2 wires the ./setup python entry) — install.sh:564 auto-sources it as a guarded no-op, so byte-identical.test.sh stays 8/8. Collision matrix (probe-decided, .superpowers/sdd/task-2-report.md): - fresh dir -> whole-file copy - sgconfig.yml exists -> structural merge into the block-list ruleDirs (idempotent); unproven shapes (flow-list / multi-key) REFUSE-LOUDLY (a naive second ruleDirs: key = duplicate-field exit 8; a clever-but- unsafe merge is a STOP-line violation) - ruff.toml exists -> REFUSE (a sibling ruff.toml wins entirely + silently disables theirs); ship getff-ruff.toml + `extend` instructions (scalar caveat surfaced if they already use extend) - pyproject [tool.ruff] -> REFUSE (a sibling ruff.toml SILENTLY overrides [tool.ruff]); ship getff-ruff.toml + [tool.ruff.lint] merge steps - re-run -> delivered config artefacts byte-identical (idempotent) Every degrade path is printed AND appended to <consumer>/.getff-python-install.log. A pre-existing .prettierignore gets `.getff/` appended idempotently; none is created. tests/install-sh/python-delivery.test.sh covers every cell + npm-inertness/activation as first-class fixtures (RED-before-GREEN on the merge/refuse logic), plus GATED live-fire: all 4 shipped ast-grep rules + both ruff TID bans fire RED on planted violations (pinned @ast-grep/cli@0.44.1 + ruff==0.15.21; SKIP when unobtainable, like cargo firing.test.ts). Wired into audit-self.yml (meta-all-wired). refresh-covers-full-delivery.test.sh made lane-aware — the Python lane is inert on npm and has its own S2 refresh semantics, out of the npm-refresh-parity gate's population (same rationale as its skill/merge/yq exclusions). SSOT row 216 appended (delivery-mechanism BUILD verdict). Prior-art: prior-art-evaluations.md#216 (thin pure-bash delivery writer — BUILD; no headless tool copies a pre-rendered multi-tool lint bundle into an existing repo with augment-first collision. ADAPT the skip/version-stamp concepts from #124/#125, REFERENCE the `ast-grep new project` #212/#185 scaffold precedent; reuses install.sh copy_safe/merge machinery, zero new deps). * fix(python-delivery): sgconfig idempotency survives trailing-comment edits + .ruff.toml fixture + empty-array guard Review-round-1 findings addressed (commit 9e9b5bac9, setup.d/45-python.sh + tests): - Important: _py_sgconfig_merge's idempotency grep required an exact-match line, so a consumer-added trailing comment on our entry (`- .getff/astgrep-rules # our rules`) was not recognised as already-present — a re-run inserted a DUPLICATE entry, tripping ast-grep exit 8 on the consumer's next scan. Fixed by stripping trailing #-comments before the compare (same shape as the existing rest="${rest%%#*}" ruleDirs: value check two lines away), bash 3.2 compatible. TDD: added a failing cell-(ii) fixture first (RED: 2 entries instead of 1), watched it fail against the unfixed code, then fixed and watched it pass. - Important: setup.d/45-python.sh:153's `.ruff.toml` (dotfile) collision branch had no fixture. Added cell-(iii-dotfile): consumer has .ruff.toml only → layer REFUSEs loudly, ships getff-ruff.toml, prints extend instructions, logs the refusal. Passed immediately (branch already existed and worked). - Minor: tests/install-sh/refresh-covers-full-delivery.test.sh's NPM_LANE_LAYERS array expansion under `set -u` would crash on bash 3.2 if the array were ever empty. Added the repo-precedent length guard (setup.d/lib.sh:281-283 shape) before expansion. Prior-art: skipped — review-fix round, no new capability --------- Co-authored-by: t <t@t.co>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Kickoff for the python-delivery-v0 umbrella — the «per-toolchain rule-pack + installer» milestone named by python-backend-v0's closure (#962/#963): a consumer Python project runs
./setup pythonand gets WORKING, FIRING enforcement (astgrep primary + ruff fast-path), CI-wired, with a post-install firing proof.Doc-only PR (one file). Grounded in a fresh installer-architecture sweep (installer is npm-only by construction:
install.sh:173-181hard-requires package.json; renderers are pure functions with zero fs writes). Key fixed decisions: Model A commit-time pre-render (Python consumers have no Node — templates ship pre-rendered with a byte-drift gate), pure-bash delivery layer, collision policy with loud degrade (never silent clobber), python row in the install fingerprint matrix.Phase -1 cold-review: 1 BLOCKER (render execution model) + 2 MAJOR fixed in one REVISE round → CONFIRMED-GO. Principle 12 satisfied (§4: T-enumeration + T-PD-A…E domain traps). Scope: Python lane only — cargo delivery stays behind its recorded trigger (its live-fire is unreachable even in our own CI); owner may override.
Placement per kickoff-staging-placement.md §1 — merge before any dispatch.