Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a63506a
Complete package-mode generation contract
alwunder Sep 3, 2026
2aa4b0b
Harden M6.1 deployment provenance analysis
alwunder Sep 3, 2026
8b57ae6
Make wrapper inference receiver-aware
alwunder Sep 3, 2026
07cc9b0
Resolve M6.1 generation review findings
alwunder Sep 3, 2026
038ab6c
Close M6.1 validation provenance gaps
alwunder Sep 3, 2026
f26c0be
Close package-data and artifact planning gaps
alwunder Sep 3, 2026
82d1111
Harden provenance and wheel metadata checks
alwunder Sep 4, 2026
368c17c
Protect selected runtime and wheel metadata inputs
alwunder Sep 4, 2026
bdf7256
Harden provenance snapshots and wheel integrity
alwunder Sep 4, 2026
86c7065
Preserve declared entry-point groups
alwunder Sep 4, 2026
6d02dd5
Harden package-data and wheel dependency contracts
alwunder Sep 4, 2026
5fa00e0
Order package wheel validation after lock preparation
alwunder Sep 4, 2026
611c33c
Harden preview and wheel dependency proofs
alwunder Sep 4, 2026
f5e3608
Harden nested Git provenance and setup config parsing
alwunder Sep 4, 2026
ddc2fee
Honor setuptools package-data exclusions
alwunder Sep 5, 2026
99a677a
Preserve runtime resource and marker constraints
alwunder Sep 5, 2026
a19d704
Resolve setuptools package source surface
alwunder Sep 5, 2026
69f42ef
Harden runtime precision and Git identity
alwunder Sep 5, 2026
9b88c90
Validate wheel dist-info identity
alwunder Sep 5, 2026
44bdf3e
Complete packaging surface and wheel security checks
alwunder Sep 5, 2026
7a440ee
Fix minor exclusions and setuptools discovery
alwunder Sep 5, 2026
d11b470
Harden staged content and wheel surfaces
alwunder Sep 5, 2026
576760e
Scan unknown textual resource extensions
alwunder Sep 5, 2026
30defc8
Harden environment and wheel path validation
alwunder Sep 5, 2026
9425631
Block unsupported uv workspace generation
alwunder Sep 5, 2026
c979773
Require proven package surface for package mode
alwunder Sep 5, 2026
476c2fc
Block ambiguous developer artifact forks
alwunder Sep 5, 2026
e8ae407
Block sparse Git worktrees before generation
alwunder Sep 6, 2026
a72ffdb
Fail closed for text encodings and dynamic setup surfaces
alwunder Sep 6, 2026
28abe37
Block escaping setuptools roots and mirror finder exclusions
alwunder Sep 6, 2026
edae41b
Reject Windows-unsafe wheel paths and relocated metadata
alwunder Sep 6, 2026
40d81fe
Promote relative runtime imports and relocated path conflicts
alwunder Sep 6, 2026
2d40350
Align setuptools defaults and package data resolution
alwunder Sep 7, 2026
de1a0c9
Guard analyzed metadata and flat discovery ambiguity
alwunder Sep 7, 2026
9f51170
Strengthen lock artifact and dependency proofs
alwunder Sep 7, 2026
ae119a4
Validate staged wheel trust and install schemes
alwunder Sep 8, 2026
ae115ac
Validate local wheel security and collisions
alwunder Sep 8, 2026
ec499f7
Harden artifact and resource validation
alwunder Sep 8, 2026
2d5c040
Resolve implicit importlib resources anchors
alwunder Sep 8, 2026
df9dc48
Harden static package and wheel analysis
alwunder Sep 8, 2026
04a20f1
Fix entry point and resource analysis contracts
alwunder Sep 8, 2026
6b128b0
Validate wheel dependency and target contracts
alwunder Sep 8, 2026
8fd8750
Validate staged wheel dependencies semantically
alwunder Sep 9, 2026
a44b079
Close wheel policy and runtime resource gaps
alwunder Sep 9, 2026
b9a419d
Handle entry-point extras and short secrets
alwunder Sep 10, 2026
4c64e77
Validate approved artifacts and source setup
alwunder Sep 11, 2026
8c6a279
Validate the complete uv sync contract
alwunder Sep 11, 2026
9e5c7e3
Guard unmodeled setuptools package data
alwunder Sep 11, 2026
a94c1b6
Fix keyword AST runtime analysis
alwunder Sep 11, 2026
bc682d7
Fix proven API bindings and staged lock root identity
alwunder Sep 11, 2026
40da085
Fix approved artifact edge context and path ownership
alwunder Sep 11, 2026
bd5ea60
Respect static project dependency and entry-point authority
alwunder Sep 11, 2026
2a75563
Honor omitted project fields and compatible resource anchors
alwunder Sep 12, 2026
0d26ebe
Preserve legacy secret scanning and resolve module resource anchors
alwunder Sep 12, 2026
94b3fd5
Recognize as_file resources and relative literal dynamic imports
alwunder Sep 12, 2026
0ce9979
Honor named setuptools layouts and positional resource text arguments
alwunder Sep 12, 2026
4888ee2
Model functional resource reads across supported Python versions
alwunder Sep 12, 2026
847198a
Enforce application wheel authority and complete resource acceptance
alwunder Sep 12, 2026
83dcead
Validate Windows kit paths and preserve explicit resource reads
alwunder Sep 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pdbuilder plan C:\path\to\repository --online --extra map
pdbuilder generate C:\path\to\repository --dry-run
pdbuilder generate C:\path\to\repository --prepare-lock --bootstrap bundled_uv
pdbuilder generate C:\path\to\repository --bootstrap bundled_uv --system-certs
pdbuilder generate C:\path\to\repository --application-wheel C:\wheels\application.whl
pdbuilder validate C:\staging\deployment-kit --static
pdbuilder validate C:\staging\deployment-kit --runtime
pdbuilder validate C:\staging\deployment-kit --runtime --dry-run
Expand Down Expand Up @@ -140,6 +141,10 @@ Generation and `all` still require an authoritative entry point and all normal r
Assessment and planning JSON use the current 1.1 output schema. Commands analyze a repository and
construct current models; they do not load arbitrary historical assessment/plan JSON as workflow
inputs. Deployment-kit and release manifests have separate schemas and compatibility checks.
Pre-M6.1 source-mode deployment manifests remain valid because new manifest fields have safe
defaults, and those kits can still be statically validated and packaged. Package mode was introduced
with M6.1 and deliberately requires a validated `application_artifact`; a package-mode manifest that
omits it is rejected with an explicit artifact-contract failure rather than a model `KeyError`.

See [docs/architecture.md](docs/architecture.md) for component boundaries and the implementation
sequence.
Expand Down Expand Up @@ -192,11 +197,14 @@ shared; environments, logs, metadata, repair, and deletion scope remain applicat

## Generating a deployment kit

Generation uses the `DeploymentPlan` as its source of truth. The default output is a separate
staging directory containing a sanitized copy of the source application plus the deployment
layer. Git/IDE state, `.env` files, tests, prior output/cache data, and credential files are not
copied. Pointing `--output-dir` at the repository root is explicit in-place generation; unknown or
locally modified file collisions are refused.
Generation uses the `DeploymentPlan` and role-aware assessment inventory as its source of truth;
it does not broadly copy the repository. Source mode stages application source, immutable runtime
resources, and required backend metadata. Deployment support, tests, documentation, examples,
development tooling, mutable state, ignored/untracked local material, unknown files, and Python
runtime caches are not staged by default. A Git source with a recorded revision is further limited
to tracked files; ordinary directories and materialized archives remain supported through the safe
inventory path. Pointing `--output-dir` at the repository root is explicit in-place generation;
unknown or locally modified file collisions are refused.

```text
Run <Application>.bat
Expand All @@ -214,6 +222,7 @@ deployment\
launch.py
diagnostics.py
wheels\ (approved artifacts only)
application\ (validated first-party wheel in package mode)
README-deployment.txt
```

Expand All @@ -231,12 +240,45 @@ using PowerShell. Neither mode modifies PATH or runs uv self-update.
Windows certificate store for corporate trust roots without disabling TLS validation, changing
certificate stores, or adding insecure hosts.

### Source and package modes

Source mode does not install the project. Its authoritative metadata entry-point module must be
structurally importable from the planned staged source roots. A source-tree entry-point candidate
is diagnostic and never replaces the authoritative installed entry point.

Package mode is selected when the installed namespace cannot be provided by the physical source
layout, or when package policy otherwise requires installation. The developer supplies an exact
first-party wheel with `--application-wheel`. PDB validates its distribution, version, wheel tags,
entry-point metadata/module, explicitly named setuptools package-data mappings, pure-Python
structure, and SHA-256 before staging it. Wildcard (`"*"`) package-data mappings are retained as
metadata but are not exhaustively asserted by the M6.1 wheel validator. End-user setup synchronizes
locked third-party dependencies with `--no-install-project`
and `--no-build`, installs approved exceptional dependency wheels, installs the first-party wheel
with `uv pip install --no-deps --no-build`, and runs `uv pip check`. It never builds the application
on the end-user machine. The application-wheel provenance is distinct from dependency
`--artifact` inputs and participates in deployment/stale-state fingerprints. PDB records the exact
wheel filename, distribution, version, contents policy, and SHA-256 separately from the assessed
source revision. Ordinary wheel metadata does not cryptographically prove that the wheel was built
from that revision; that relationship remains a developer-controlled build/release assertion.
Changing the exact wheel bytes changes runtime state. Renaming byte-identical wheel bytes does not
rebuild an otherwise identical environment, although the staged filename and release ZIP change.

Existing application deployment-support files are inventory evidence, not standalone runtime
inputs. They are not copied merely because they are launchers or live at the repository root.

### Developer preparation

Every real generation runs pinned `uv lock --check`. A stale lock stops generation without
rewriting it. A missing lock also stops unless `--prepare-lock` explicitly authorizes a local
repository mutation; URL inputs cannot use that option. The builder then runs
`uv lock --python <minor>`, checks the result, reports the changed `uv.lock`, and never commits it.
For Git inputs with a recorded revision, generation compares deployment inputs identified in both
the recorded `HEAD` tree and the current working-tree inventory. Modified, deleted, or unstaged-
renamed tracked metadata, lockfiles, application source, and runtime resources are refused rather
than labeling changed working-tree contents as clean revision provenance. Unrelated tracked
documentation and harmless untracked files do not trigger that gate. Untracked and ignored
runtime-looking files are not silently staged; required runtime material must be tracked or
supplied by the application wheel.

The intended source-control workflow is to create a deployment-preparation branch, assess and
plan, explicitly prepare missing metadata, generate outside the repository, validate the staged
Expand Down Expand Up @@ -414,8 +456,9 @@ do not make live OpenAI API calls or execute target code.
explicitly selected optional dependencies. A present `uv.lock` is statically traversed for the
selected Windows/Python/extra graph and locked wheel/source-distribution policy.
- Private GitHub repositories are out of scope for the MVP.
- Current generation is focused on the two source-mode reference applications. General package
deployment and a complete offline Python/package bundle remain future work.
- Current generation supports source-compatible projects and install-oriented projects that supply
a validated pure-Python first-party wheel. Native first-party wheels and a complete offline
Python/package bundle remain future work.
- The `uv_managed` backend is pilot ready, not universally compatible with every Windows Python
application. Developer-side runtime validation is not a substitute for application-specific
Standard User GUI, external-service, and organizational network-policy testing.
Expand Down
123 changes: 123 additions & 0 deletions docs/acceptance/pr9-alias-keyword-lock-root-2026-09-11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# PR #9: proven bindings, keyword reads, and legacy lock roots

Starting head: `a94c1b69f7934a7a0f89f725c17f135ee3296cea`.
Review submitted: `2026-09-11T12:28:22Z`.
Accounting before the next review: 111 findings, 108 unresolved inline threads,
three review-level-only findings, and one NOT_APPLICABLE inline finding.
This correction does not resolve threads, dismiss reviews, or authorize merge.

## Fresh findings and reproduction

| Finding | Comment | Correction |
| --- | --- | --- |
| P1: Track aliased environment APIs when collecting secrets | 3989107557 | Precompute explicit stdlib import bindings before visiting runtime reads. |
| P2: Preserve the root identity for legacy source manifests | 3989107568 | Cross-check structural lock identity; block actual rootless legacy projects before generation. |
| P2: Read the dynamic-import name keyword | 3989107573 | Use the existing `call_argument` for `name`. |
| P2: Resolve keyword-form pkgutil resource reads | 3989107579 | Use the same helper for `package` and `resource`. |

The initial regression run, before production edits, produced **55 failures and
22 passes**. Aliased `os.getenv`, imported/aliased `getenv`, and imported/aliased
`environ.get` calls were present in the AST but retained alias spellings and
produced no configuration requirements. Thus their names did not reach manifest
secret lists or configured-value scanning. Keyword dynamic imports did not stage
their excluded-scope targets; keyword pkgutil reads did not stage their resources.
The legacy source kit was generated but failed static lock identity validation.

## Bounded AST contract

Explicit absolute imports provide file-level binding evidence, independently of
the textual order of imports and function declarations. Wildcard imports,
relative imports, and unrelated user functions are not proof of stdlib origin.
This is not runtime import execution or a general lexical name-resolution engine.

The environment matrix covers canonical and aliased os modules, directly imported
and aliased getenv functions, and directly imported/aliased environ objects,
including get/subscript reads, positional/keyword keys, defaults, dynamic keys,
and non-identifier environment names. Aliased secrets reach assessment, planning,
manifest name lists, configured-value lookup, staged resource scans, and
application/approved-wheel scans. Synthetic-value assertions cover serialization
and exception/log output; short configured secrets retain their fail-closed rule.

Dynamic imports use the existing proven importlib/builtin bindings, literal
absolute dotted-name policy, and local-module resolver. Keyword names follow the
same source-root, initializer, containment, staging, and deployment-mode paths as
positional names. Dynamic, f-string, relative, and malformed names remain unresolved.

Pkgutil accepts positional, mixed, and fully keyword-bound arguments for the
existing proven aliases. Positional values win duplicate bindings, as in the
shared helper. Extra arguments, unrelated keywords, dynamic values, unsafe paths,
and namespace-only packages remain unresolved. A keyword argument followed by a
bare positional resource is invalid Python syntax, not another supported form.
Nested safe resources and declared package-data behavior retain existing rules.

The one bounded binding audit also corrected aliases of already-supported runtime
APIs in os, subprocess, ctypes, shutil, and webbrowser; resource directory reads
through os.listdir/scandir aliases; and relative imports incorrectly supplying
stdlib resource binding evidence. Focused tests accompany these changes. No new
API family, general argument binder, or generic name-resolution engine was added.

## Actual uv 0.12.5 evidence and identity decision

The explicit developer script `scripts/verify_legacy_lock_root.py` was run against
`uv 0.12.5 (210d1f678 2026-08-14 x86_64-pc-windows-msvc)` with `uv lock --python 3.12`.
It creates disposable fixtures outside the repository. Applications are not run.

| Fixture | Actual root representation |
| --- | --- |
| Ordinary PEP 621 source project | `source = { virtual = "." }` |
| PEP 621 package-mode project with setuptools/src layout | `source = { editable = "." }` |
| PEP 621 source project with selected `feature` extra | `source = { virtual = "." }`; metadata lists the extra |
| Build-system-only pyproject + literal setup.py, zero dependencies | **No package records** |
| Build-system-only pyproject + setup.cfg, zero dependencies | **No package records** |

Both actual legacy locks contain only `version = 1`, `revision = 3`, and
`requires-python = ">=3.12"`. Assessment identifies `legacy-demo` and source mode;
the backend-dependency blocker does not apply. Before this correction, generation
succeeded but `APPROVED_ARTIFACT_LOCK_IDENTITY` failed because no root identity
could be proved. Afterward, `LEGACY_LOCK_ROOT_UNIDENTIFIABLE` blocks planning and
generation, including an explicit dry-run action, before creating the kit.
The remedy is standardized `[project]` metadata and a regenerated lock.

A new TOML-only helper returns the exact name of one unambiguous virtual/editable
`.` root. Static validation cross-checks canonical distribution names from the
application artifact, standardized project metadata, and structural lock root;
contradictions fail closed. There is no application-ID/directory-name inference,
source reassessment, or metadata execution. Root-bearing older source manifests,
including synthetic legacy compatibility fixtures, remain valid. Such fixtures
are not claimed to be the output of the actual rootless uv legacy workflow.

Merely persisting the legacy name would not supply the absent root graph, so the
allowed early planning blocker is used instead of a new manifest field. Analysis
schema **1.4** and planning schema **1.3** remain unchanged. Static lock proof is
still unconditional: an empty approved-artifact list does not bypass reverse
artifact completeness.

## Read-only acceptance checks

| Repository | Unchanged SHA | Result |
| --- | --- | --- |
| SimpleGeorefGUI | `f484570d89fb1f9e9170fac915475358dfc1234e` | package; ENTRYPOINT_REQUIRES_PACKAGE_MODE; BLOCKED_PENDING_APPLICATION_WHEEL; 13 Python / 77 data members |
| Geo Map Explanation Extractor | `5e7b321d0aeb9ba1d586bfc548c79793d84c6033` | source / SOURCE_COMPATIBLE |
| TN Coordinate Converter | `e1e7a1588c37a99c2d02efaf3eef3d04636f12f0` | source / SOURCE_COMPATIBLE; existing reviewed kit STATIC_VALID |

Before/after Git working-tree status also matched. Configuration-name lists did
not change: SGG has APPDATA, LOCALAPPDATA, SIMPLE_GEOREF_GUI_DATA_DIR, XDG_DATA_HOME;
Geo has LOCALAPPDATA and OPENAI_API_KEY; TN has none. No environment values are
included in this report. TN's existing kit retains the approved
`proxy_tools-0.1.0-py3-none-any.whl` artifact and `proxy-tools==0.1.0` identity.

## Verification

Focused final regression run: **127 passed, 430 deselected** (new regression file,
keyword wheel-secret propagation, and existing backend-only metadata cases).
The single complete suite passed: **998 passed, 3 skipped in 259.25 seconds**
(previous baseline: 874 passed, 3 skipped). `ruff check .` and
`git diff --check` passed. The final diff contains only the four corrections,
the bounded audit, regression tests, and this reproduction/acceptance evidence.

The complete suite retains coverage of the preceding keyword AST correction,
MANIFEST/include-package-data and setuptools-scm guards, exact sync contract,
approved-artifact identity/reverse completeness, mode-aware pip checks, entry
points, short secrets, LOCALAPPDATA ordering, wheel/dependency policy, resource
and inventory rules, package surfaces, wheel security/integrity/collisions,
provenance, prepare-lock/dry-run/reporting/rollback, and deterministic packaging.
Loading