diff --git a/.fossil-settings/AGENTS.md b/.fossil-settings/AGENTS.md index ed1d58ee..496c1da3 100644 --- a/.fossil-settings/AGENTS.md +++ b/.fossil-settings/AGENTS.md @@ -28,7 +28,7 @@ Versioned fossil settings (one setting value or glob list per file) for this dua - **No negation exists in fossil globs.** Git's `/bin/*` + `!exception` pattern becomes: ignore `bin/*` wholesale and explicitly `fossil add` the tracked exceptions (ignore-glob never affects already-managed files, so they stay tracked). The exception set is whatever git tracks under an ignored tree - at the time of writing: `bin/AGENTS.md`, `bin/*.cmd`, `bin/*.kit`, `bin/*.tcl`, `bin/*.sh`, `bin/*.bash`, `.claude/settings.json` (shared claude harness hooks/permissions; session-local `.claude` files stay ignored), `.claude/skills/**` (project agent skills - synced copies of `.agents/skills/**`, which is not git-ignored and needs no exception), plus force-tracked one-offs (`bin/libssp-0.dll`, `bin/runtime/README.md` - guidance, not build output; a `!` negation cannot re-include it because git does not descend into the excluded `bin/runtime` directory, so `git add -f` is the only mechanism, `src/vfs/punk9magicsplat.vfs/lib/nmake/x86_64-w64-mingw32-nmakehlp.exe`). Derive the current set with the verification comparison below rather than trusting this list. - A bare directory name prunes that whole tree; `*` crosses `/`; git patterns intended to match at any depth need an additional `*/` variant; `#` comment lines are honoured. - Do not add the fossil-generated names (`manifest`, `manifest.uuid`, `manifest.tags`) to `ignore-glob` - fossil handles them itself. -- **Nested `.gitignore` files are git-only**: ignore files inside subtrees (e.g. the project-layout templates under `src/project_layouts/`) are honoured by git as nested ignores of the outer repo but invisible to fossil - template content they match is untracked in git yet managed by fossil. Treat such divergence as a signal to review the git side (usually `git add -f` of the affected template files). +- **Nested `.gitignore` files are git-only**: ignore files inside subtrees are honoured by git as nested ignores of the outer repo but invisible to fossil - content they match is untracked in git yet managed by fossil. Treat such divergence as a signal to review the git side. (The former instance of this class - the project-layout templates under `src/project_layouts/` carrying live `.gitignore` payloads - is resolved structurally: payloads are stored inert as `gitignore.in` and materialized at project generation, G-012. Any NEW nested `.gitignore` appearing under a layout store is the hazard recurring and should be converted to the inert form, not force-added.) - **Case sensitivity differs**: git ignore matching is case-insensitive on Windows (`core.ignorecase`), fossil glob matching is case-sensitive - e.g. a `todo.txt` pattern hits vendored `TODO.txt` in git but not fossil. ### Safe sync procedure (mandatory for any ignore-rule change, not only on request) diff --git a/AGENTS.md b/AGENTS.md index 252e95d2..b0800d61 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -211,7 +211,7 @@ The project version is fully independent of module versions. A module bump (even - `lib/` (root) — Build output target for `tclsh src/make.tcl libs` - `modules_tcl8/`, `modules_tcl9/` — Tcl version-specific build output targets - `lib_tcl8/`, `lib_tcl9/` — Tcl version-specific build output targets - - `src/project_layouts/` — Thin project layout payloads (structure, scripts, docs, manifests - no stored bootsupport/vfs module snapshots; G-087, achieved - see goals/archive/G-087-thin-project-layouts.md). The build's thin-layout sync step (`make.tcl modules`/`libs`/`packages`/`bakehouse`) keeps each layout's `src/make.tcl`, `src/build.tcl` and bootsupport `include_modules.config` copies current, and syncs the punk.project payload into the `punk::mix::templates` modpod source tree; `dev project.new` composes each layout's overlay chain (vendor then custom tier, `@` derived folders, `.anti` deletion markers - see the store README) via `layout_materialize`, injects bootsupport modules/libs from the generating shell at generation time, and seeds generated-project identity metadata (punkproject.toml, CHANGELOG.md, punkorigin.toml provenance baseline) programmatically. Agents must not directly edit files under `src/project_layouts/` unless the user explicitly names a path there or specifically requests layout changes; never hand-edit the synced copies (they are punkcheck-managed build outputs). + - `src/project_layouts/` — Thin project layout payloads (structure, scripts, docs, manifests - no stored bootsupport/vfs module snapshots; G-087, achieved - see goals/archive/G-087-thin-project-layouts.md). The build's thin-layout sync step (`make.tcl modules`/`libs`/`packages`/`bakehouse`) keeps each layout's `src/make.tcl`, `src/build.tcl` and bootsupport `include_modules.config` copies current, refreshes every vendor/punk layout's inert `gitignore.in` payload from the canonical root `.gitignore` (G-012 - VCS-config payloads are stored inert and materialized to their live name at project generation; never store a literal `.gitignore` in a layout), and syncs the punk.project payload into the `punk::mix::templates` modpod source tree; `dev project.new` composes each layout's overlay chain (vendor then custom tier, `@` derived folders, `.anti` deletion markers - see the store README) via `layout_materialize`, injects bootsupport modules/libs from the generating shell at generation time, and seeds generated-project identity metadata (punkproject.toml, CHANGELOG.md, punkorigin.toml provenance baseline) programmatically. Agents must not directly edit files under `src/project_layouts/` unless the user explicitly names a path there or specifically requests layout changes; never hand-edit the synced copies (they are punkcheck-managed build outputs). ## Repo-wide Notes diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 61fff089..54c661e5 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -95,7 +95,7 @@ Two layers with a deliberate dependency direction (the class never depends on th - **Payload/target consistency checks (G-133 + G-134), all advisory.** At the same post-merge seam, a bake classifies each binary library in the merged tree by header (`punkboot::utils::binary_arch_classify` - PE/ELF/Mach-O, honest unknowns) against the kit's target platform; wrong-arch libraries outside platform-discriminated subdirs (canonical `-` names, vendor spellings like `win-x64`) earn recapped `BUILD-WARNING`s. After assembly, a kit declaring smoke-require packages (`mapvfs.toml` `smokerequire` key) has each one plain-`package require`d inside the freshly built artifact via its tclsh subcommand - the only check that sees resolution-order defects (wrong-arch version shadowing); cross-target kits skip with a stated reason. The assembled image is also probed for its zip offset convention (G-134, `punkboot::utils::kit_offsetstyle_report` over `punk::zip::archive_info`): a FILE-relative attached payload warns (the pipeline emits archive-relative; the G-128 stamper refuses file-relative by default), no-zip/plain results stay silent. Same guarded-require degradation; `make.tcl check` reports all three. None guarantees statics, pure-tcl packages with binary deps, or version preference beyond the declared smoke set. Sources: `src/AGENTS.md`, `src/runtime/AGENTS.md`, `src/modules/punkboot/utils-999999.0a1.0.tm`. - **Kit icon step (G-057 + G-128).** Every kit a bake builds gets a `.resources.toml` sidecar (deployed beside `bin/`) recording the build-time icon choice - default `src/runtime/punkshell.ico`, overridable by a root `punkshell.ico` in the kit's own custom `.vfs` folder (pre-merge) - with sha256 identity and provenance lifted from the icon's G-135 assetorigin record. win32-target kits get the icon embedded as PE `RT_ICON`/`RT_GROUP_ICON` behind a single seam (`::punkboot::kit_icon_process`): the vendored punkres portable stamper (`src/tools/punkres`, built to `bin/punkres(.exe)` by the make.tcl tool step) is selected when present and works from any build host; otherwise the twapi arm (tcl-sfe mechanism) serves windows hosts with nothing built. Both arms share one semantic (delete all icon/group entries, write ids 1..N; the group is NAMED from the icon file's uppercased rootname - `PUNKSHELL` - with language adopted from the replaced group) and stamp a per-kit copy of the payload-free raw runtime prefix BEFORE payload attach; punkres can also stamp a FINISHED kit post-hoc, preserving an appended zip payload (archive-relative moved verbatim; file-relative refused by default, shifted with a consent flag). Non-PE targets skip as not applicable; a host where neither mechanism serves skips with a combined notice naming the punkres build remedy; the sidecar is written in every case. Sources: `src/AGENTS.md`, `bin/AGENTS.md`, `src/vfs/AGENTS.md`, `src/tools/AGENTS.md`. - **Buildsuites and the kit family.** `src/buildsuites/suite_tcl90/` builds Tcl/Tk/tcllib from source with a pinned zig toolchain and produces the runtime kit family (plain / punk / bi) plus artifact metadata (G-096-G-117 era: see archived goals G-096, G-098, G-102, G-103, G-107); artifacts publish to the punkbin repo that `bin/punk-runtime.cmd` fetches from. Both suites also emit the punkbin LIBRARY tier (G-138, achieved): verified tcllib/tcllibc installs as generation-tagged immutable zips (`lib/allplatforms` + `lib/`, embedded schema-v2 class=library records, punkzip-deterministic) - the `library-artifacts` step in each recipe. The tier's `` axis includes cross-built lanes: suite_tcl90's `tcllibc-linux` step (G-140, achieved) cross-builds the critcl accelerators for linux-x86_64 via critcl driving `zig cc -target` (stubs linkage - no linux host involved), structurally ELF-gated on the build host and consumed by the punk9linux kit payload. Consumption (G-139, achieved): `make.tcl libfetch` materializes declared artifacts into the untracked `bin/packages/` tier with server-trust consent, and the PACKAGES_tcl libs phase + per-.vfs payload declarations with `source_root = "packages"` (G-115) feed the deployed `lib_tcl` trees and kit vfs payloads - the vendored tcllib trees are retired, and embedded records ride into baked kits. `src/buildsuites/suite_tcl86/` is the 8.6 sibling (G-099 + G-100, both achieved): a Tcl 8.6 windows runtime (static + dynamic shells, `tcl86t.dll`, on-disk lib tree - no zipfs, so no self-contained kit) with thread 2.8 + tclvfs + Tk 8.6 + tklib + tcllib(+tcllibc critcl accelerators) companions, gated against the 8.6 core/thread/tclvfs testsuites with tcllib/tklib on a record tier and an opt-in `test-tk`; punkshell's own runtests is censused on that runtime at parity with a same-day native-8.6 baseline. Suite child shells scrub `TCL__TM_PATH` as well as TCLLIBPATH/TCL_LIBRARY/TK_LIBRARY - without it a census measures the machine's module trees. The 8.6 kit container strategy remains in-flux - see "In-flux areas". -- **Project generation.** `dev project.new` composes thin layouts from `src/project_layouts/` (overlay chain with `.anti` deletion markers and `name@base` derivation - G-087, achieved) and injects bootsupport modules from the generating shell at generation time. +- **Project generation.** `dev project.new` composes thin layouts from `src/project_layouts/` (overlay chain with `.anti` deletion markers and `name@base` derivation - G-087, achieved; VCS-config payloads stored inert as `gitignore.in` and materialized to `.gitignore` at composition - G-012) and injects bootsupport modules from the generating shell at generation time. - **Workflow overview.** `tclsh src/make.tcl workflow` prints the embedded ASCII data-flow overview of the build/release pipeline, with its own update contract in `src/AGENTS.md`. This section deliberately summarises rather than copies it. ## Test harness diff --git a/CHANGELOG.md b/CHANGELOG.md index ba17e626..dc58fc5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to Entries are newest-first; one bullet per notable change. See the root `AGENTS.md` "Project Versioning" section for the bump policy. +## [0.39.5] - 2026-08-01 + +- Project-layout template payloads no longer self-censor in git (G-012): layout + `.gitignore` payloads are stored inert as `gitignore.in` and materialized to + `.gitignore` at project generation (punk::mix::commandset::layout 0.3.0 - + rename map in `layout_materialize_renames`, staging-time rename after overlay + composition, in-place fast path withheld from inert-payload folders). + make.tcl's thin-layout sync now refreshes every vendor/punk layout's + `gitignore.in` from the canonical root `.gitignore` (punkcheck-tracked), so + generated projects receive current ignore rules and template files can no + longer silently drop out of git tracking. + ## [0.39.4] - 2026-08-01 - make.tcl piped output no longer leaks orphan ANSI fragments ('0;1m', '[0m', a lone diff --git a/GOALS-archive.md b/GOALS-archive.md index 04bee020..500ba1bd 100644 --- a/GOALS-archive.md +++ b/GOALS-archive.md @@ -28,6 +28,10 @@ Acceptance: a subshell started with an ssh-channel-backed and a tk-widget-backed Scope: src/modules/punk/console-999999.0a1.0.tm; src/modules/punk/repl-999999.0a1.0.tm; src/modules/punk/repl/codethread-999999.0a1.0.tm Acceptance: from a running punk session's code interp, without `repl eval`: `console_fact_get` returns the same values the parent sees and a fact set in the parent is immediately visible; a terminal query (e.g. `get_cursor_pos` or `dec_get_mode`) against the default console succeeds and cooperates with the repl reader (no lost or garbled input); a console constructed and owned by code-interp code is operated on locally (no round-trip to the parent); the existing console test suites pass and single-interp (non-repl) usage is unchanged. +### G-012 [achieved 2026-08-01] Template system: inert VCS-config payloads and explicit layout refresh → detail: goals/archive/G-012-template-payload-safety.md +Scope: src/project_layouts/; src/make.tcl; src/modules/punk/mix/ (layout instantiation); fauxlink module (bootsupport 0.2.0 - promoted if chosen as mechanism) +Acceptance: a scan of src/project_layouts finds no file named .gitignore, and git check-ignore --no-index over every layout file matches only root-.gitignore rules (nested rules provably inert); a project generated from each affected layout receives a working .gitignore whose content matches the canonical payload/target; after editing a canonical source (e.g. root .gitignore), the make.tcl template-refresh step updates the derived layout payloads (punkcheck-tracked), covering vendor/punk layouts as well as custom/_project; the previously hidden template files (layout READMEs, vendored TODO-class files) remain git-tracked without per-file force-add exceptions. (Achieved with the custom/_project clause stale - that store level was retired by G-087 stage 5 after drafting; the refresh covers every vendor/punk layout. Evidence in the detail file.) + ### G-015 [achieved 2026-07-07] Punk executable `script` subcommand: reliable non-interactive piped/script execution → detail: goals/archive/G-015-script-subcommand-piped-stdin.md Scope: src/vfs/_config/punk_main.tcl; src/lib/app-punkshell/punkshell.tcl (script path or a leaner dedicated app package) Acceptance: piping commands to ` script` runs them and terminates at stdin EOF with no trailing `exit` required, exit code 0 on success; a failing piped command terminates the process with a nonzero exit code and the error on stderr, never landing in an interactive shell regardless of console availability or PUNK_PIPE_EOF; ` script [...]` executes the file with conventional ::argv0/::argv and propagates its error status the same way; the script path installs none of the `shell` subcommand's shellfilter stacks/transforms and the launch plumbing itself emits nothing on stdout/stderr (the current stub's stderr diagnostics removed) so exec-style callers see only the script's own output; the motivating example works with no package require boilerplate: piping `dev projects.work **` to ` script` emits the matching-project table and exits 0, because the script interp carries the default punk shell module/alias environment. diff --git a/GOALS.md b/GOALS.md index 1edb57aa..4b77c2a6 100644 --- a/GOALS.md +++ b/GOALS.md @@ -113,10 +113,6 @@ Detail: goals/G-010-subshell-tree-navigation.md Scope: src/modules/punk/console-999999.0a1.0.tm; src/modules/opunk/console-999999.0a1.0.tm; src/modules/punk/repl-999999.0a1.0.tm Detail: goals/G-011-console-stderr-semantics.md -### G-012 [proposed] Template system: inert VCS-config payloads and explicit layout refresh -Scope: src/project_layouts/; src/make.tcl; src/modules/punk/mix/ (layout instantiation); fauxlink module (bootsupport 0.2.0 - promoted if chosen as mechanism) -Detail: goals/G-012-template-payload-safety.md - ### G-013 [proposed] Raw mode as the repl's default input mode Scope: src/modules/punk/repl-999999.0a1.0.tm; src/modules/punk/console-999999.0a1.0.tm Detail: goals/G-013-raw-mode-default.md diff --git a/goals/G-027-derived-project-pull-updates.md b/goals/G-027-derived-project-pull-updates.md index ecd204f9..c69aa680 100644 --- a/goals/G-027-derived-project-pull-updates.md +++ b/goals/G-027-derived-project-pull-updates.md @@ -117,8 +117,12 @@ What a pull may touch splits by ownership, not by file type: ## Notes -- Related: G-012 (inert template payloads and the make.tcl template-refresh - step feed what a pull delivers), G-016/G-017 (project discovery for +- Related: G-012 (achieved 2026-08-01 - see goals/archive/G-012-template-payload-safety.md; + its inert template payloads and the make.tcl template-refresh step feed what a pull + delivers. G-012 also recorded that AGENTS.md layout payloads - when they arrive per this + goal's documentation-ownership design - are the same live-config hazard class and need + the same inert-storage + materialize-at-generation treatment as the .gitignore payloads), + G-016/G-017 (project discovery for re-locating a moved origin), G-026 (clean-checkout policy on the source), G-005/G-006 (remote artifact channels if remote pull proceeds). - The 2025-04 tomlish checkin "update bootsupport and make.tcl from punkshell" diff --git a/goals/G-031-componentized-kit-boot.md b/goals/G-031-componentized-kit-boot.md index 970f43dc..fbadd330 100644 --- a/goals/G-031-componentized-kit-boot.md +++ b/goals/G-031-componentized-kit-boot.md @@ -55,7 +55,8 @@ permanently own - a thousand lines of boot code. - Boot core carries its own version/identity so a kit can report the boot vintage it embeds (G-025 stamping is the natural vehicle). - Layout skeletons follow through the established sync channels (custom/ - _project sync step now; G-012/G-027 for the rest) - noted in completion + _project sync step now; G-012 (achieved 2026-08-01 - see + goals/archive/G-012-template-payload-safety.md)/G-027 for the rest) - noted in completion reports, never hand-synced. ## Alternatives considered @@ -78,7 +79,7 @@ permanently own - a thousand lines of boot code. script subcommand's behaviour. - Related: G-027 (ownership + pull channel this is designed for), G-025 (boot-core vintage reporting), G-032 (punk::args-defined dispatch built on - the registration model), G-012 (layout payload hygiene), G-018 (plain tclsh + the registration model), G-012 (layout payload hygiene - achieved 2026-08-01), G-018 (plain tclsh kits deliberately carry NO punk boot layer - out of scope here). - G-033 (archived) recorded a fork-drift datapoint for this goal: the proj: scope prefix and its `::punkboot::proj_root_find` walk-up landed in diff --git a/goals/G-043-subshell-definition-plugins.md b/goals/G-043-subshell-definition-plugins.md index a1b07bf2..20c6a6e8 100644 --- a/goals/G-043-subshell-definition-plugins.md +++ b/goals/G-043-subshell-definition-plugins.md @@ -106,7 +106,7 @@ Phases: punk::cap pkg_unregister "destroy api objects?" review; silent unhandled-capability declarations (punk.isbogus); hardcoded _multivendor whitelist in the templates handler (not this goal's to fix - noted for the templates/layout update-story work under - G-012/G-027). + G-012 (achieved 2026-08-01 - see goals/archive/G-012-template-payload-safety.md)/G-027). - The templates handler's registration-time vs call-time path resolution split (and its documented staleness edge for long-running shells) is the precedent for deciding when a punk.subshell declaration's resources are resolved. diff --git a/goals/G-047-declared-primary-vcs.md b/goals/G-047-declared-primary-vcs.md index c9b22ed0..b7526382 100644 --- a/goals/G-047-declared-primary-vcs.md +++ b/goals/G-047-declared-primary-vcs.md @@ -37,7 +37,8 @@ The original G-047 draft (2026-07-08) declared a single team-wide primary with t - Layout templates seed `vcs = "fossil"` as the generated-project default plus the punkproject.local.toml ignore rules in both ignore systems. - Validation of the declared field against the VCS systems actually present (make.tcl / project.new) is follow-on work, deliberately out of scope. - G-012 relationship (recorded 2026-07-24 after overlap review; neither file previously - referenced the other): this goal seeds template payload (the vcs default plus the + referenced the other; G-012 achieved 2026-08-01 - see goals/archive/G-012-template-payload-safety.md): + this goal seeds template payload (the vcs default plus the ignore rules) - G-012's inert-storage plus explicit-refresh machinery is how such layout payload propagates; seeding rides its refresh step, never hand-syncs. - G-065 relationship: its vendor manifest schema shares punkproject.toml-or-sibling diff --git a/goals/G-086-light-project-layout.md b/goals/G-086-light-project-layout.md index a45aafd1..bf6cd926 100644 --- a/goals/G-086-light-project-layout.md +++ b/goals/G-086-light-project-layout.md @@ -13,4 +13,4 @@ serversecretsync (c:/repo/jn/serversecretsync) was seeded 2026-07-14 by hand rat - Default mechanism (user decision 2026-07-14): vendor punk::libunknown + punk::packagepreference into the light layout as the bootstrap minimum, so generated projects get punkshell's package-resolution control rather than relying on bare path ordering alone. The seeded preamble stays small: project path setup plus the bootstrap requires, before anything else runs. - Pure-Tcl path ordering remains the inner layer the bootstrap itself depends on - the preamble must be correct before any package require, including the requires that load the bootstrap modules themselves. -- Related goals: G-012 (template payload safety - inert VCS-config payloads apply to this layout too), G-027 (derived-project pull updates - how light projects receive infrastructure refreshes), G-035 (mixed .tm/pkgIndex provision characterization backing libunknown/packagepreference behaviour), G-029 (packaged test modules - the light harness should stay compatible with that direction). +- Related goals: G-012 (achieved 2026-08-01 - see goals/archive/G-012-template-payload-safety.md; template payload safety - its inert VCS-config payload treatment applies to this layout too), G-027 (derived-project pull updates - how light projects receive infrastructure refreshes), G-035 (mixed .tm/pkgIndex provision characterization backing libunknown/packagepreference behaviour), G-029 (packaged test modules - the light harness should stay compatible with that direction). diff --git a/goals/G-136-generated-project-icon-seeding.md b/goals/G-136-generated-project-icon-seeding.md index 5ca2ac79..faac80de 100644 --- a/goals/G-136-generated-project-icon-seeding.md +++ b/goals/G-136-generated-project-icon-seeding.md @@ -89,7 +89,7 @@ unbranded so it reads "replace me" rather than as a product identity. - Related: G-086 - interaction. Whether the light layout declares an icon slot is decided there; this goal's acceptance is written so a layout may decline without that counting as a failure. -- Related: G-012 - sibling surface. The overwrite-on-regeneration behaviour is +- Related: G-012 (achieved 2026-08-01 - see goals/archive/G-012-template-payload-safety.md) - sibling surface. The overwrite-on-regeneration behaviour is the same question as its explicit layout-refresh semantics. - The placeholder's geometry carries two constraints that are easy to undo by accident, recorded in `src/assets/logo/AGENTS.md`: bezel and crest are ONE diff --git a/goals/G-012-template-payload-safety.md b/goals/archive/G-012-template-payload-safety.md similarity index 56% rename from goals/G-012-template-payload-safety.md rename to goals/archive/G-012-template-payload-safety.md index cc731bd5..cb60e0e6 100644 --- a/goals/G-012-template-payload-safety.md +++ b/goals/archive/G-012-template-payload-safety.md @@ -1,6 +1,6 @@ # G-012 Template system: inert VCS-config payloads and explicit layout refresh -Status: proposed +Status: achieved 2026-08-01 Scope: src/project_layouts/; src/make.tcl; src/modules/punk/mix/ (layout instantiation); fauxlink module (bootsupport 0.2.0 - promoted if chosen as mechanism) Goal: project layouts carry no live nested VCS-config files - template .gitignore payloads are stored inert (renamed, or fauxlink-encoded) and materialized at project generation - and src/make.tcl has an explicit punkcheck-tracked step that refreshes layout payloads from their canonical sources. Acceptance: a scan of src/project_layouts finds no file named .gitignore, and git check-ignore --no-index over every layout file matches only root-.gitignore rules (nested rules provably inert); a project generated from each affected layout receives a working .gitignore whose content matches the canonical payload/target; after editing a canonical source (e.g. root .gitignore), the make.tcl template-refresh step updates the derived layout payloads (punkcheck-tracked), covering vendor/punk layouts as well as custom/_project; the previously hidden template files (layout READMEs, vendored TODO-class files) remain git-tracked without per-file force-add exceptions. @@ -32,6 +32,20 @@ payload drift is unmanaged. ## Approach +**Mechanism decision (recorded 2026-08-01, implementation start): neutral rename.** +Payloads are stored under an inert name (`gitignore.in`) and materialized to their live +name (`.gitignore`) at generation. Chosen over fauxlink because: (a) fauxlink's model in +this codebase is zero-byte filename-as-pointer (layout refs) - real authored payload +content does not fit it; (b) a fauxlink target flattens every layout's payload to one +canonical file, removing the possibility of per-layout canonical payloads, and pointing +at the out-of-store repo-root `.gitignore` would need a new resolution convention; +(c) rename is dependency-free and the layout system already has a single materialization +funnel (`layout_materialize`) where a small explicit rename map (extensible to future +live-config payloads such as `.gitattributes`) hooks in cleanly. The four vendor/punk +`.gitignore` payloads are treated as drifted mirrors of the canonical root `.gitignore` +(the goal context's "essentially a copy") - the make.tcl template-refresh step rederives +them from root, so the vintage variants are eliminated rather than preserved. + 1. **Store VCS-config payloads inert.** Two candidate mechanisms; the choice is an implementation decision to be recorded here when made: - *Neutral rename*: payload stored as e.g. `_gitignore` or `gitignore.in`; layout @@ -67,6 +81,69 @@ payload drift is unmanaged. - **Do nothing on the git side (fossil sees the files)** - rejected: git is the day-to-day VCS; a mirror having the truer view is a symptom, not a solution. +## Progress + +Landed 2026-08-01 (activated and implemented in one session at user request): + +- **Inert storage** - the four vendor/punk `.gitignore` payloads renamed to `gitignore.in`; + the `custom/punk/othersample@sample-0.1/.gitignore.anti` marker renamed to + `gitignore.in.anti` (.anti markers target store names). No file named `.gitignore` + remains under src/project_layouts or in the modpod payload source folder. +- **Materialization** - punk::mix::commandset::layout 0.3.0: new + `lib::layout_materialize_renames` map ({gitignore.in .gitignore}) with private helpers + `_find_inert_payload_relpaths`/`_apply_materialize_renames`; `layout_stage_chain` renames + inert payloads to live names after composing all layers (new `materialized` return key); + `layout_materialize` withholds the in-place fast path from inert-payload folders so the + rename only ever happens in staging. Both store-name and materialized-name presence at + one location errors. Characterization: src/tests/modules/punk/mix/testsuites/layout/ + materialize.test (+5 tests, 25/25; full punk/mix subtree 71 pass / 1 known skip). +- **Template refresh** - make.tcl's thin-layout sync (the `sync_layouts` make-step recorded + in src/project_layouts/.punkcheck) now syncs the canonical REPO ROOT .gitignore into every + vendor/punk layout as `gitignore.in` alongside the existing boot-script/manifest pairs + (which remain gated on the layout carrying src/make.tcl); workflow_text DIAGRAM 1b + + release step 9 updated. The four payloads are byte-identical mirrors of root - the vintage + variants are eliminated as drift per this goal's "essentially a copy" framing. +- **Modpod path** - the store->modpod sync carries `gitignore.in` and its prune removed the + stale modpod `.gitignore`; the rebuilt templates-0.2.0.tm was verified to carry the + byte-identical payload. (The kit-baked copy inside punk91.exe etc is stale until the + routine vfscommonupdate + bake refresh - noted, not a source defect.) + +Verification evidence (acceptance clause by clause): + +1. "scan of src/project_layouts finds no file named .gitignore" - VERIFIED (recursive force + listing; also none in the modpod payload source folder). +2. "git check-ignore --no-index over every layout file matches only root-.gitignore rules" - + VERIFIED: full sweep matched exactly one file, src/project_layouts/.punkcheck, by the + ROOT rule `*.punkcheck`; no nested rule exists to fire. +3. "project generated from each affected layout receives a working .gitignore whose content + matches the canonical payload" - VERIFIED end-to-end (punk91 src script driver, FOSSIL_HOME + diverted): generated projects from punk.basic, punk.minimal, punk.project and + punk.sample-0.1 each received `.gitignore` byte-identical to root; punk.othersample (the + .anti deletion fixture) received none, by design. Generation from the module-carried + layout (punk.project#2) returns old-variant content only from the stale kit-baked + templates module; the freshly built templates-0.2.0.tm carries the byte-identical payload + (verified by direct member extraction). +4. "editing a canonical source updates the derived payloads (punkcheck-tracked), covering + vendor/punk" - VERIFIED both directions: a transient marker line appended to root + .gitignore propagated to all four payloads on `make.tcl libs` (punkcheck-recorded + "PROJECT LAYOUT update" events) and was removed again after reverting root. **Stale + clause:** "...as well as custom/_project" - the _project pseudo-vendor store level was + retired for layouts by G-087 stage 5 (2026-07-19, after this goal was drafted 2026-07-06): + no custom/_project layout exists to cover, and custom-tier payloads are authored + overrides (not derived mirrors) by design. Flagged for the user at completion - the + refresh covers every layout under vendor/punk, which is the live reading of the clause. +5. "previously hidden template files remain git-tracked without per-file force-add + exceptions" - VERIFIED: the fc1c474c README files (project-0.1/{bin,lib,modules}/ + README.md, bin/runtime/README.md) are tracked and match no ignore rule; the previously + invisible modpod-copy README trees now appear as ordinary (trackable) files. The + accidental-ignore class is structurally impossible: no nested .gitignore exists to fire. + +Remaining manual items: none for the goal itself. The stale-kit refresh (vfscommonupdate + +bake) is routine build maintenance. The binary-glob/fossil-commit note from G-087 (generated +projects' trailing fossil commit aborts on binary payload - layouts ship no binary-glob) is +a different problem class (missing fossil-side setting, not a live-config hazard) and stays +out of this goal's acceptance - candidate follow-on goal. + ## Notes - Affected today: `src/project_layouts/vendor/punk/{basic,minimal,project-0.1,sample-0.1}/.gitignore`. @@ -97,6 +174,10 @@ payload drift is unmanaged. .tm modules) because thin layouts ship no binary-glob settings - this goal's inert VCS-config payload treatment is the designated fix. Layouts without binaries (sample/derived fixtures) commit cleanly. +- Related (activation survey 2026-08-01, goals_xref score G-012): G-086 (light layout's + VCS-config payloads get the same inert treatment), G-031 (thin-main skeleton propagates + via this goal's refresh step), G-136 (icon seeding's overwrite-on-regeneration rides the + same refresh semantics) - all three already point here; back-pointers recorded at activation. - G-047 relationship (recorded 2026-07-24 after overlap review): G-047 seeds punkproject.toml workflow defaults plus ignore rules into layout payload - a new payload class for this goal's inert-storage plus refresh machinery to carry; the diff --git a/punkproject.toml b/punkproject.toml index 7e293bcb..b7f749f0 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,6 +1,6 @@ [project] name = "punkshell" -version = "0.39.4" +version = "0.39.5" license = "BSD-2-Clause" url = "https://www.gitea1.intx.com.au/jn/punkshell" #packager: declared identity for published artifacts (declarative, not proof - diff --git a/src/AGENTS.md b/src/AGENTS.md index a2ce27f6..cc45f89d 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -70,7 +70,7 @@ Recovery after a wrong path guess: - Use `tclsh src/make.tcl vfscommonupdate` to rebuild `_vfscommon.vfs`. The REPLACE confirmation prompts on an interactive terminal; unattended/agent runs must pass `-confirm 0` (with the default `-confirm 1` and a piped/closed stdin, make.tcl aborts fast with guidance instead of reading stdin - do not pipe `y`). - `tclsh src/make.tcl workflow` prints an embedded ASCII data-flow overview of the build/release workflow (release-ready command sequence, source→outputs folder flow, kit assembly, keyed notes). The text lives in `::punkboot::workflow_text` in `src/make.tcl` - embedded rather than a data file so it travels with the make.tcl copies seeded into generated projects. **Update contract (agents):** whenever build data flow changes - a make.tcl subcommand added/removed/repurposed, a source or output folder added or rerouted, a propagation target added, a gate (staleness/provenance/confirm) or deploy behaviour changed - update the workflow text in the same change-set. Keep it plain ASCII, max line width 100, and preserve the RELEASE SEQUENCE / DIAGRAM / KEY-NOTES / MAINTENANCE structure; verify by running `tclsh src/make.tcl workflow` (and once under `PUNKBOOT_PLAIN=1`). Adding/changing a subcommand also means: SUMMARIES + HELPTEXTS + its braced `punk::args::define` block (+ SUBGROUPS) in `::punkboot::argdoc`, `known_commands`, the plain `punkboot_gethelp` text, and a project-version bump (make.tcl interface is product surface per root AGENTS.md). Layout make.tcl copies pick the change up via the thin-layout sync step in any `make.tcl modules`/`libs`/`packages`/`bakehouse` run - do not hand-sync them. - make.tcl subcommands and flags are punk::args-declared (G-030): `tclsh src/make.tcl help ?subcommand?` or ` -help` shows tabled usage; invalid arguments produce punk::args usage errors. The dispatch degrades to plain scan/help when the bootsupport punk::args (or its rendering stack) is stale or unavailable; `PUNKBOOT_PLAIN=1` forces the degraded mode for troubleshooting. The `::punkboot::argdoc` definitions are braced file-style blocks using the G-045 authoring mechanisms — `-&` record continuations, tstr placeholders pulling SUMMARIES/HELPTEXTS and the shared `OPT_*` option fragments, explicit `@form -synopsis` — with `-help` bodies expanding as deferred display fields so the HELPTEXTS block indentation deliberately renders as a centred Description (no `@normalize` re-basing); see src/modules/AGENTS.md "punk::args definition authoring ergonomics" before editing them or authoring similar definitions. -- Uncommitted `make.tcl`-generated outputs may be batched into one commit, regardless of how many `make.tcl` invocations produced them. This covers punkcheck-managed build outputs that are VCS-tracked: `src/bootsupport/`, `_vfscommon.vfs/modules` + `/lib`, declared per-kit `*.vfs/lib_tcl/` subfolders, the thin-layout sync copies (`src/project_layouts/vendor/punk//src/{make.tcl,build.tcl}` + bootsupport manifest copies), and the module-shipped layout payload under `src/modules/punk/mix/#modpod-templates-*/templates/project_layouts/` (G-087: synced from `src/project_layouts` - never hand-edit the modpod copy). (Root `modules/`, `lib/`, `modules_tcl/`, `lib_tcl/` are gitignored and never committed.) Each module's old→new version rename is atomic; a regeneration reflects one build-output refresh, not independent hand-edits. This is a carve-out from generic "split aggressively" commit guidance for punkcheck-managed build outputs only — it does not cover user-curated VFS content (`_config/`, per-kit `*.vfs/` outside declared `lib_tcl` subfolders, `_aside/`, `mkzipfix.vfs`, `_vfscommon.vfs/doc`), which commits separately per its own concerns. +- Uncommitted `make.tcl`-generated outputs may be batched into one commit, regardless of how many `make.tcl` invocations produced them. This covers punkcheck-managed build outputs that are VCS-tracked: `src/bootsupport/`, `_vfscommon.vfs/modules` + `/lib`, declared per-kit `*.vfs/lib_tcl/` subfolders, the thin-layout sync copies (`src/project_layouts/vendor/punk//src/{make.tcl,build.tcl}` + bootsupport manifest copies + the inert `gitignore.in` payload copies refreshed from the root `.gitignore` - G-012), and the module-shipped layout payload under `src/modules/punk/mix/#modpod-templates-*/templates/project_layouts/` (G-087: synced from `src/project_layouts` - never hand-edit the modpod copy). (Root `modules/`, `lib/`, `modules_tcl/`, `lib_tcl/` are gitignored and never committed.) Each module's old→new version rename is atomic; a regeneration reflects one build-output refresh, not independent hand-edits. This is a carve-out from generic "split aggressively" commit guidance for punkcheck-managed build outputs only — it does not cover user-curated VFS content (`_config/`, per-kit `*.vfs/` outside declared `lib_tcl` subfolders, `_aside/`, `mkzipfix.vfs`, `_vfscommon.vfs/doc`), which commits separately per its own concerns. - **Boot-precondition gate (G-125).** A bake refuses any kit whose merged `.vfs` supplies no tcl library: the kit is listed under `FAILED KITS` with a reason naming the cause, and NOTHING is written - no `src/_build/`, no deploy, and the previously deployed `bin/` is left byte-identical. This is deliberately a failure rather than a warning: the deploy step deletes the old kit before copying the new one, so the pre-gate behaviour replaced a working shell with an artifact that died at startup with `application-specific initialization failed: Cannot find a usable init.tcl`. The check is structural and non-executing (so it covers cross-target kits too): `init.tcl` in `tcl_library/`, `lib/tcl./` or `tcl./` - the third for runtimes whose archive mounts at the executable's own path rather than `//zipfs:/app`, so `[info library]` is `/tcl8.6` (the androwish/undroidwish zipfs backport for 8.6 does this) - plus one companion file a real Tcl library carries beside it (`tm.tcl`, `package.tcl`, `auto.tcl`, `clock.tcl`, `history.tcl`, `word.tcl`) or an `encoding/` directory - without that second test the `lib/BWidget1.10.1/init.tcl` every punkshell kit carries would answer for a tcl library it cannot provide. It reads the MERGED tree rather than asking whether extraction ran, so a `.vfs` that legitimately supplies its own tcl library (`src/vfs/punk8_statictwapi.vfs`, `src/vfs/punk9test.vfs`) builds and deploys unchanged. **Remedy when a kit is refused:** the usual cause is that the runtime's own payload could not be extracted - read the recapped `BUILD-WARNING` naming what was tried, then either fix extraction (a driving tclsh with no zipfs needs punk::zip >= 0.2.0 in bootsupport - see the extraction bullet above), point the kit at a runtime that carries a payload, or have the kit's `.vfs` supply a tcl library itself. The predicate is `punkboot::utils::vfs_boot_library_report` called through a guarded require, exactly as the dirty-src provenance check is: a stale or missing bootsupport snapshot degrades the gate to a `NOTE` rather than failing every kit. `tclsh src/make.tcl check` reports whether the gate is `ACTIVE` or `UNAVAILABLE`. - **Payload/target consistency checks (G-133), both ADVISORY** - warnings are recapped `BUILD-WARNING`s and the kit still builds and deploys (unlike the G-125 gate). (a) **Binary-arch scan**, at the same post-merge seam as the gate: every binary library (`*.dll`/`*.so`/`*.dylib`) in the merged tree is classified by header bytes (`punkboot::utils::binary_arch_classify` - PE Machine field, ELF e_machine, Mach-O incl. universal; unclassifiable content is honestly `unknown` and never warned about) against the kit's target platform. Structural and non-executing, so it runs for cross-target kits too (measured ~30-140ms per kit, avg ~93ms across the 12 assembled trees). Libraries under a platform-discriminated subdir - canonical `-` platform-dir names, the universal `macosx` folder, or a recognised vendor spelling (`win-x64` etc; the lists are namespace variables in `punkboot::utils`) - are exempt: multi-arch payloads are legitimate there. First real sweep (2026-07-27) found a true latent instance: `zint.dll` 2.13.0 in `src/vfs/punk8win.vfs/lib_tcl8/` is 32-bit (i386) and can never load in the x64 tcl8 kits (punk86/punkbi/punksys) that carry it - those bakes warn until the payload is fixed. (b) **Smoke-require probe**: a kit declaring packages in `src/runtime/mapvfs.toml` (`smokerequire` key - see `src/runtime/AGENTS.md`) has each one plain-`package require`d INSIDE the freshly built artifact via its tclsh subcommand, which exits cleanly even on runtimes whose full repl teardown is fragile. This is the only check that observes actual package RESOLUTION - the punkluck86 2026-07-27 incident class (a higher-versioned wrong-arch Thread shadowing the runtime's working copy on plain require) is invisible to structural checks because the working file exists too. Failures are recapped naming kit, package and the actual error; cross-target kits skip with a stated reason; undeclared kits run nothing new; the probe only runs when the kit actually rebuilds. **What the checks do NOT guarantee:** statically linked packages, pure-tcl packages whose binary dependency lives elsewhere, and version-preference outcomes are visible only to the smoke probe - and only for the declared package set; the arch scan proves nothing about loadability beyond architecture, and an `unknown` classification is silence, not a pass. Both degrade to a NOTE when the bootsupport `punkboot::utils` snapshot is stale (same guarded require as the G-125 gate); `tclsh src/make.tcl check` reports the scan's ACTIVE/UNAVAILABLE state and the currently declared smoke-require kits. - **Kit offset-style pin (G-134), ADVISORY** - at the same seam family, every ASSEMBLED kit image is probed with `punk::zip::archive_info` (via `punkboot::utils::kit_offsetstyle_report`, same guarded-require degradation to a NOTE; `make.tcl check` reports ACTIVE/UNAVAILABLE): a FILE-relative attached zip payload earns a recapped `BUILD-WARNING` naming the kit, because the pipeline emits ARCHIVE-relative by construction and the G-128 stamper refuses file-relative by default - a warning here means an assembly path regressed the output convention. **What the pin does NOT cover:** `plain` and `none` results (a bare zip, or no attached zip at all - the metakit kit shape, and any unreadable input) are silence, never warnings - the pin asserts the offset CONVENTION of an attached zip, not the presence of one; and it asserts only what make.tcl's own assembly paths EMIT - `punk::zip::mkzip -offsettype file` (and modpod's equivalent) remain available for deliberate manual creation of file-relative artifacts, and file-relative INPUT artifacts remain tolerated by the G-124 reader and normalized by any re-bake. diff --git a/src/make.tcl b/src/make.tcl index 7699d3e3..8df9a39c 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -2674,7 +2674,8 @@ RELEASE SEQUENCE (the developer order that satisfies the staleness + provenance (7) build tclsh src/make.tcl vfscommonupdate -confirm 0 (8) build tclsh src/make.tcl bake -confirm 0 kits; close running kit shells first [K5] (9) commit tracked build outputs src/bootsupport, thin-layout script/ - manifest copies (src/project_layouts + + manifest/gitignore.in payload copies + (src/project_layouts + templates modpod payload), src/vfs/_vfscommon.vfs @@ -2712,9 +2713,11 @@ DIAGRAM 1 - DATA FLOW: SOURCE -> BUILT PACKAGES -> PROPAGATION TARGETS DIAGRAM 1b - THIN-LAYOUT SYNC (part of modules/libs/packages/bakehouse runs) ---------------------------------------------------------------------------- - src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config + .gitignore src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config | - | punkcheck-recorded copies into each vendor layout carrying src/make.tcl + | punkcheck-recorded copies: root .gitignore -> every vendor layout's inert + | gitignore.in payload (G-012; materialized to .gitignore at generation), + | scripts/manifests -> each vendor layout carrying src/make.tcl v src/project_layouts/vendor/punk//src/... (thin layouts: scripts, docs, | manifests - no module snapshots) @@ -6634,9 +6637,11 @@ if {$::punkboot::command in {bakehouse packages libs}} { if {$::punkboot::command in {bakehouse packages modules libs}} { ######################################################## #templates - thin-layout sync (G-087 stage 3; see DIAGRAM 1b in ::punkboot::workflow_text) - #sync boot scripts (build.tcl, make.tcl) and bootsupport include_modules.config manifests into the - #thin vendor layouts (those that carry src/make.tcl), then sync the punk.project layout payload from - #the store into the punk::mix::templates modpod source tree so the built module ships it. + #sync the canonical root .gitignore into every vendor layout as the inert gitignore.in + #payload (G-012 - materialized to .gitignore at project generation), sync boot scripts + #(build.tcl, make.tcl) and bootsupport include_modules.config manifests into the thin + #layouts that carry src/make.tcl, then sync the punk.project layout payload from the + #store into the punk::mix::templates modpod source tree so the built module ships it. #Layouts store no bootsupport/vfs module snapshots - 'dev project.new' injects bootsupport into #generated projects from the generating shell at generation time. set layout_bases [list {*}{ @@ -6650,10 +6655,6 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { } set project_layouts [glob -nocomplain -dir $layoutbase -type d -tail *] foreach layoutname $project_layouts { - if {![file exists $layoutbase/$layoutname/src/make.tcl]} { - #layout doesn't carry boot scripts (e.g minimal, sample-0.1) - nothing to sync - continue - } set config [dict create {*}{ -make-step sync_layouts }] @@ -6662,16 +6663,27 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { $tpl_installer set_source_target $sourcefolder $layoutbase/$layoutname set tpl_event [$tpl_installer start_event $config] #---------- + #G-012: every layout's gitignore payload is a derived mirror of the canonical root + #.gitignore, stored inert as gitignore.in (materialized to .gitignore in the + #generated project by punk::mix::commandset::layout::lib::layout_materialize). + #Canonical source is the REPO root .gitignore ($projectroot, not $sourcefolder). set pairs [list {*}{ - } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ - } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } [list $projectroot/.gitignore $layoutbase/$layoutname/gitignore.in] {*}{ } ] - #bootsupport manifests: sync only into bootsupport modules folders the layout already carries - foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { - set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config - if {[file exists $src_manifest]} { - lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + if {[file exists $layoutbase/$layoutname/src/make.tcl]} { + #layout carries boot scripts - sync them too (layouts that don't, e.g minimal, + #sample-0.1, receive only the gitignore payload) + lappend pairs {*}{ + } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ + } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } + #bootsupport manifests: sync only into bootsupport modules folders the layout already carries + foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { + set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config + if {[file exists $src_manifest]} { + lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + } } } diff --git a/src/modules/punk/AGENTS.md b/src/modules/punk/AGENTS.md index c9b411e3..97b376f3 100644 --- a/src/modules/punk/AGENTS.md +++ b/src/modules/punk/AGENTS.md @@ -40,7 +40,7 @@ Source of truth for all modules under the `punk::*` namespace. This is the prima - Private helpers go in `namespace eval private { ... }` blocks. - Keep `namespace export` lists alphabetized. - The `#modpod-*` folders contain files that get packed into `.tm` module archives during build — do not flatten them. -- `mix/#modpod-templates-*/templates/project_layouts/` is a build-managed copy of the thin punk.project layout, synced from `src/project_layouts/vendor/punk/project-0.1` by make.tcl's thin-layout sync step (G-087) - edit the store layout, never this copy. It ships inside the built `punk::mix::templates` module so a bare kit can list and generate the punk.project layout (resolution via punk::cap::handlers::templates >= 0.3.0). +- `mix/#modpod-templates-*/templates/project_layouts/` is a build-managed copy of the thin punk.project layout, synced from `src/project_layouts/vendor/punk/project-0.1` by make.tcl's thin-layout sync step (G-087) - edit the store layout, never this copy. It ships inside the built `punk::mix::templates` module so a bare kit can list and generate the punk.project layout (resolution via punk::cap::handlers::templates >= 0.3.0). Like the store, its `.gitignore` payload is held inert as `gitignore.in` and materialized to `.gitignore` at generation (G-012). - Follow the parent `src/modules/AGENTS.md` "Versioning And Releases" rules: bump `-buildversion.txt` on any API or behavior change and append a changelog comment line documenting the change. ## Verification diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/.gitignore b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/.gitignore deleted file mode 100644 index e1889f93..00000000 --- a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ - -/bin/* -!/bin/*.cmd -!/bin/*.kit -!/bin/*.tcl -!/bin/*.sh -!/bin/*.bash -/lib/ -#The directory for compiled/built Tcl modules -/modules/ -/vendorbuilds/ - -#Temporary files e.g from tests -/tmp/ - -/logs/ -**/_aside/ -**/_build/ -scratch* - -#Built documentation -/html/ -/man/ -/md/ -/doc/ - -/test* - - -#Built tclkits (if any) -*.exe - -#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) -_FOSSIL_ -.fos -.fslckout -*.fossil - -#miscellaneous editor files etc -*.swp -*.log - -*.punkcheck - -todo.txt - -zig-cache/ -zig-out/ -/release/ -/debug/ -/build/ -/build-*/ -/docgen_tmp/ diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/README.md b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/README.md new file mode 100644 index 00000000..3b3c1f98 --- /dev/null +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/README.md @@ -0,0 +1,3 @@ +Project scripts and executables + +These files usually shouldn't be modified directly as they are built from the files in the src folder \ No newline at end of file diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/runtime/README.md b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/runtime/README.md new file mode 100644 index 00000000..ec844bdc --- /dev/null +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/runtime/README.md @@ -0,0 +1,26 @@ +runtime Tcl Executables are installed here under the appropriate os_architecture folder. +e.g + windows 64bit binaries under win32-x86_64 + linux 64 bit binaries under linux-x86_64 + +The bin/punk-runtime.cmd cross-platform script can be used to download prebuilt Tcl binaries. +e.g ./bin/punk-runtime.cmd fetch +This will detect the platform and architecture, creating the containing folder as necessary. + +To see existing installed runtimes: + ./bin/punk-runtime.cmd list +Or to compare local runtimes with those available on the artifact server: + ./bin/punk-runtime.cmd list -remote + + An installed runtime can then be used to call the src/make.tcl file. + +e.g - initial check + ./bin/punk-runtime.cmd run src/make.tcl check + +e.g - to build (or just copy with latest version number from src if build not required) modules to projectdir/modules + ./bin/punk-runtime.cmd run src/make.tcl modules + for libs & modules + ./bin/punk-runtime.cmd run src/make.tcl packages + + + diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/gitignore.in b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/gitignore.in new file mode 100644 index 00000000..79773aaa --- /dev/null +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/gitignore.in @@ -0,0 +1,108 @@ + +#while bin is primarily an output - some items here are for bootstrapping - so while they aren't the source - we install and source-control them. +/bin/* +!/bin/AGENTS.md +!/bin/*.cmd +!/bin/*.kit +!/bin/*.tcl +!/bin/*.sh +!/bin/*.bash + + +#The directories for compiled/built Tcl packages (libs and modules) +#These are purely 'output' folders - no need to track +/lib/ +/lib_tcl8/ +/lib_tcl9/ +/modules/ +/modules_tcl8/ +/modules_tcl9/ + +#Temporary files e.g from tests +/tmp/ + +.vscode +#claude harness config: track the shared project settings (hooks/permissions) and project skills, +#ignore everything else (session-local settings etc) +.claude/* +!.claude/settings.json +!.claude/skills/ +.omo + +/logs/ +**/_aside/ +**/_build/ +scratch* + +#Built documentation +/html/ +/man/ +/md/ +/doc/ + +/test* +/src/testdata +/src/scriptapps/test_* + +#G-115 demonstration kit payload - materialized from the src/vfs/punkdeclare.vfs.toml +#declaration (vendor tree + consent-gated bin/packages tier); reproducing it from the +#declaration is the point, so it is never committed +/src/vfs/punkdeclare.vfs/lib_tcl9/ + +#G-127 per-platform payload staging - materialized from %platform% entries in +#src/vfs/.vfs.toml (one subtree per consuming kit target) and selected into +#each kit's merged image at bake time; regenerable staging, never committed +/src/vfs/*.vfs/_targets/ + +#review +/src/docgen + +#local developer notes +/localdoc/ + +#Built tclkits (if any) +*.exe + + +#subfolder for temporary reference files - not source controlled +#we may use git clone to get a copy of the reference files - but we don't want to track them in the repo +TEMP_REFERENCE + +#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) +_FOSSIL_ +.fos +.fslckout +*.fossil + +#fossil-generated checkout artifacts - regenerated on every fossil checkin/checkout per the +#versioned 'manifest' setting (value 'rut'); fossil auto-manages them and they must not be +#git-tracked. Anchored: nested manifest-named files elsewhere are real content. +#See .fossil-settings/AGENTS.md for the git+fossil coexistence contract. +/manifest +/manifest.uuid +/manifest.tags + +#miscellaneous editor files etc +*.swp +*.log + +*.punkcheck + +todo.txt + +zig-cache/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +/~/ + +#Node +/node_modules/ +/package-lock.json +/package.json diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/lib/README.md b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/lib/README.md new file mode 100644 index 00000000..693ecd33 --- /dev/null +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/lib/README.md @@ -0,0 +1,6 @@ +Tcl Libraries which use the pkgIndex.tcl system to load. +Each library will usually have its own folder in the lib folder. +Some groups of libraries may have a deeper structure - usually with a pkIndex.tcl at the top level, +and individual pkgIndex.tcl files further down. + +These files shouldn't be modified directly as they are built or copied from the files in the src folder diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/modules/README.md b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/modules/README.md new file mode 100644 index 00000000..884a0680 --- /dev/null +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/modules/README.md @@ -0,0 +1,9 @@ +Tcl Modules +These are packaged as .tm file extension and the loadable locations are controlled by functions such as tcl::tm::path add|list|remove + +Via the make process, the modules may come from from src/vendormodules - being modules not generally developed within the current project. + +They are built from src/modules for those that are directly part of the project. + +These files shouldn't be modified directly as they are built or copied from the files in the src folder structure. + \ No newline at end of file diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl index 7699d3e3..8df9a39c 100644 --- a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl @@ -2674,7 +2674,8 @@ RELEASE SEQUENCE (the developer order that satisfies the staleness + provenance (7) build tclsh src/make.tcl vfscommonupdate -confirm 0 (8) build tclsh src/make.tcl bake -confirm 0 kits; close running kit shells first [K5] (9) commit tracked build outputs src/bootsupport, thin-layout script/ - manifest copies (src/project_layouts + + manifest/gitignore.in payload copies + (src/project_layouts + templates modpod payload), src/vfs/_vfscommon.vfs @@ -2712,9 +2713,11 @@ DIAGRAM 1 - DATA FLOW: SOURCE -> BUILT PACKAGES -> PROPAGATION TARGETS DIAGRAM 1b - THIN-LAYOUT SYNC (part of modules/libs/packages/bakehouse runs) ---------------------------------------------------------------------------- - src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config + .gitignore src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config | - | punkcheck-recorded copies into each vendor layout carrying src/make.tcl + | punkcheck-recorded copies: root .gitignore -> every vendor layout's inert + | gitignore.in payload (G-012; materialized to .gitignore at generation), + | scripts/manifests -> each vendor layout carrying src/make.tcl v src/project_layouts/vendor/punk//src/... (thin layouts: scripts, docs, | manifests - no module snapshots) @@ -6634,9 +6637,11 @@ if {$::punkboot::command in {bakehouse packages libs}} { if {$::punkboot::command in {bakehouse packages modules libs}} { ######################################################## #templates - thin-layout sync (G-087 stage 3; see DIAGRAM 1b in ::punkboot::workflow_text) - #sync boot scripts (build.tcl, make.tcl) and bootsupport include_modules.config manifests into the - #thin vendor layouts (those that carry src/make.tcl), then sync the punk.project layout payload from - #the store into the punk::mix::templates modpod source tree so the built module ships it. + #sync the canonical root .gitignore into every vendor layout as the inert gitignore.in + #payload (G-012 - materialized to .gitignore at project generation), sync boot scripts + #(build.tcl, make.tcl) and bootsupport include_modules.config manifests into the thin + #layouts that carry src/make.tcl, then sync the punk.project layout payload from the + #store into the punk::mix::templates modpod source tree so the built module ships it. #Layouts store no bootsupport/vfs module snapshots - 'dev project.new' injects bootsupport into #generated projects from the generating shell at generation time. set layout_bases [list {*}{ @@ -6650,10 +6655,6 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { } set project_layouts [glob -nocomplain -dir $layoutbase -type d -tail *] foreach layoutname $project_layouts { - if {![file exists $layoutbase/$layoutname/src/make.tcl]} { - #layout doesn't carry boot scripts (e.g minimal, sample-0.1) - nothing to sync - continue - } set config [dict create {*}{ -make-step sync_layouts }] @@ -6662,16 +6663,27 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { $tpl_installer set_source_target $sourcefolder $layoutbase/$layoutname set tpl_event [$tpl_installer start_event $config] #---------- + #G-012: every layout's gitignore payload is a derived mirror of the canonical root + #.gitignore, stored inert as gitignore.in (materialized to .gitignore in the + #generated project by punk::mix::commandset::layout::lib::layout_materialize). + #Canonical source is the REPO root .gitignore ($projectroot, not $sourcefolder). set pairs [list {*}{ - } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ - } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } [list $projectroot/.gitignore $layoutbase/$layoutname/gitignore.in] {*}{ } ] - #bootsupport manifests: sync only into bootsupport modules folders the layout already carries - foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { - set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config - if {[file exists $src_manifest]} { - lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + if {[file exists $layoutbase/$layoutname/src/make.tcl]} { + #layout carries boot scripts - sync them too (layouts that don't, e.g minimal, + #sample-0.1, receive only the gitignore payload) + lappend pairs {*}{ + } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ + } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } + #bootsupport manifests: sync only into bootsupport modules folders the layout already carries + foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { + set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config + if {[file exists $src_manifest]} { + lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + } } } diff --git a/src/modules/punk/mix/commandset/layout-999999.0a1.0.tm b/src/modules/punk/mix/commandset/layout-999999.0a1.0.tm index e30f7fc9..d50b30d4 100644 --- a/src/modules/punk/mix/commandset/layout-999999.0a1.0.tm +++ b/src/modules/punk/mix/commandset/layout-999999.0a1.0.tm @@ -232,6 +232,19 @@ namespace eval punk::mix::commandset::layout { # layout_materialize is the entry point; project.new copies from its result path. # -- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- + # G-012: inert VCS-config payloads. A payload file stored under a tail name that is a + # key of materialize_renames would be LIVE configuration under its real name (git + # treats any .gitignore in the tree as live), so layouts store it under the inert key + # name and it is renamed to the materialized value name when the layout's effective + # content is composed (layout_stage_chain). layout_materialize withholds the in-place + # fast path from folders carrying inert payloads, so the rename only ever happens in + # the disposable staging dir - never in the store. .anti markers target STORE names + # (renames run after every layer is composed). The map is the extension point for + # future live-config payload classes (e.g .gitattributes). + # -- --- --- --- --- --- --- --- --- --- --- + variable materialize_renames {gitignore.in .gitignore} + punk::args::define { @id -id ::punk::mix::commandset::layout::lib::layout_resolve_chain @cmd -name punk::mix::commandset::layout::lib::layout_resolve_chain\ @@ -334,7 +347,11 @@ namespace eval punk::mix::commandset::layout { deleting it. Returns a dict: path (stagingdir), chain, deletions (relative paths removed - by .anti markers), copied (number of files copied)." + by .anti markers), copied (number of files copied), materialized (list of + {from to} relative-path pairs of inert VCS-config payloads renamed to + their live names - G-012: gitignore.in stored inert in the store becomes + .gitignore in the composed folder; .anti markers always target store + names, since the rename runs after every layer is composed)." @values -min 2 -max 2 chain -type list -help\ "Ordered list of layout source folders, lowest priority first @@ -376,7 +393,9 @@ namespace eval punk::mix::commandset::layout { } incr copied [_merge_copy_into $sourcefolder $stagingdir] } - return [dict create path $stagingdir chain $chain deletions $deletions copied $copied] + #G-012: with every layer composed under store names, rename inert payloads to their live names + set materialized [_apply_materialize_renames $stagingdir] + return [dict create path $stagingdir chain $chain deletions $deletions copied $copied materialized $materialized] } punk::args::define { @@ -388,12 +407,15 @@ namespace eval punk::mix::commandset::layout { "Resolves the named layout's overlay chain (layout_resolve_chain) within its store and returns a folder holding the effective layout content. - When the chain is a single folder containing no .anti markers (the common - case - e.g the thin punk.project layout, or any module-carried layout) that - folder is returned as-is (staged 0) and no copying occurs. Otherwise the - chain is composed into a staging directory (layout_stage_chain) and the - staged folder is returned (staged 1) - the caller may delete it when done - (the default location is deterministic, so a later call recomposes it). + When the chain is a single folder containing no .anti markers AND no inert + VCS-config payloads (G-012: files named as keys of + layout_materialize_renames, e.g gitignore.in) that folder is returned + as-is (staged 0) and no copying occurs. Otherwise the chain is composed + into a staging directory (layout_stage_chain) and the staged folder is + returned (staged 1) - the caller may delete it when done (the default + location is deterministic, so a later call recomposes it). Inert payloads + always force staging: their rename to live names (.gitignore) must never + touch the store. Layout folders whose store position does not follow the /{vendor,custom}// shape (including any @@ -406,7 +428,9 @@ namespace eval punk::mix::commandset::layout { 0 if it is the store folder itself chain - ordered contributing folders, lowest priority first deletions - relative paths removed by .anti markers (staged only) - copied - number of files copied into staging (staged only)" + copied - number of files copied into staging (staged only) + materialized - {from to} relative-path pairs of inert payloads renamed + to live names (staged only; G-012)" @leaders -min 1 -max 1 layoutname -type string -optional 0 -help\ "Visible layout name as shown by 'dev project.layouts' (e.g punk.project)" @@ -452,16 +476,21 @@ namespace eval punk::mix::commandset::layout { } } } - #fast path - a single-source chain with no .anti markers is usable in place - if {[llength $chain] == 1 && ![llength [_find_anti_relpaths [lindex $chain 0]]]} { - return [dict create path [lindex $chain 0] staged 0 chain $chain deletions [list] copied 0] + #fast path - a single-source chain with no .anti markers and no inert payloads is + #usable in place. Inert VCS-config payloads (G-012) force staging: their rename to + #live names must never touch the store. + if { [llength $chain] == 1 + && ![llength [_find_anti_relpaths [lindex $chain 0]]] + && ![llength [_find_inert_payload_relpaths [lindex $chain 0]]] + } { + return [dict create path [lindex $chain 0] staged 0 chain $chain deletions [list] copied 0 materialized [list]] } if {$opt_stagingdir eq ""} { set sanitized [regsub -all {[^A-Za-z0-9_.-]} $layoutname _] set opt_stagingdir [file join [punk::lib::tempdir] punk_layout_staging $sanitized] } set stageinfo [layout_stage_chain $chain $opt_stagingdir] - return [dict create path [dict get $stageinfo path] staged 1 chain $chain deletions [dict get $stageinfo deletions] copied [dict get $stageinfo copied]] + return [dict create path [dict get $stageinfo path] staged 1 chain $chain deletions [dict get $stageinfo deletions] copied [dict get $stageinfo copied] materialized [dict get $stageinfo materialized]] } punk::args::define { @@ -531,6 +560,101 @@ namespace eval punk::mix::commandset::layout { return $antis } + punk::args::define { + @id -id ::punk::mix::commandset::layout::lib::layout_materialize_renames + @cmd -name punk::mix::commandset::layout::lib::layout_materialize_renames\ + -summary\ + "Return the inert-payload rename map applied at layout materialization"\ + -help\ + "Returns a dict of {inertTail materializedTail} (G-012). Layout payload + files stored under an inert tail name - so they are not live + configuration in the layout store (git never reads gitignore.in) - are + renamed to their materialized tail name (.gitignore) when a layout's + effective content is composed by layout_stage_chain. The map is the + extension point for future live-config payload classes (e.g + .gitattributes stored as gitattributes.in)." + @values -min 0 -max 0 + } + proc layout_materialize_renames {} { + variable materialize_renames + return $materialize_renames + } + + punk::args::define { + @id -id ::punk::mix::commandset::layout::lib::_find_inert_payload_relpaths + @cmd -name punk::mix::commandset::layout::lib::_find_inert_payload_relpaths\ + -summary\ + "Recursively collect inert-payload files below a layout folder"\ + -help\ + "Internal helper for the overlay merge primitive. Returns the relative + paths of files whose tail is an inert-payload store name (a key of + layout_materialize_renames) anywhere below basefolder." + @values -min 1 -max 2 + basefolder -type string + prefix -type string -optional 1 + } + proc _find_inert_payload_relpaths {basefolder {prefix ""}} { + #manual args - see PUNKARGS ::punk::mix::commandset::layout::lib::_find_inert_payload_relpaths + variable materialize_renames + if {$prefix eq ""} { + set here $basefolder + } else { + set here [file join $basefolder $prefix] + } + set found [list] + foreach entry [_dir_entries $here] { + if {$prefix eq ""} { + set rel $entry + } else { + set rel [file join $prefix $entry] + } + if {[dict exists $materialize_renames $entry]} { + lappend found $rel + } elseif {[file isdirectory [file join $here $entry]]} { + lappend found {*}[_find_inert_payload_relpaths $basefolder $rel] + } + } + return $found + } + + punk::args::define { + @id -id ::punk::mix::commandset::layout::lib::_apply_materialize_renames + @cmd -name punk::mix::commandset::layout::lib::_apply_materialize_renames\ + -summary\ + "Rename inert-payload files in a composed folder to their live names"\ + -help\ + "Internal helper for the overlay merge primitive. Renames every + inert-payload file below folder (tail matching a key of + layout_materialize_renames) to its materialized tail name in place, and + returns the list of applied {from to} relative-path pairs. Errors when + both the inert name and its materialized name exist at the same location + - a layout carrying both is contradictory (the materialized name is live + VCS config and must never be store content)." + @values -min 1 -max 1 + folder -type string + } + proc _apply_materialize_renames {folder} { + #manual args - see PUNKARGS ::punk::mix::commandset::layout::lib::_apply_materialize_renames + variable materialize_renames + set applied [list] + foreach relpath [_find_inert_payload_relpaths $folder] { + set newtail [dict get $materialize_renames [file tail $relpath]] + set relbase [file dirname $relpath] + if {$relbase eq "."} { + set tgtrel $newtail + } else { + set tgtrel [file join $relbase $newtail] + } + set tgt [file join $folder $tgtrel] + if {[file exists $tgt]} { + error "layout materialize: both inert payload '$relpath' and materialized name '$tgtrel' are present - the materialized name is live VCS config and must never be layout store content" + } + file rename -- [file join $folder $relpath] $tgt + lappend applied [list $relpath $tgtrel] + } + return $applied + } + punk::args::define { @id -id ::punk::mix::commandset::layout::lib::_merge_copy_into @cmd -name punk::mix::commandset::layout::lib::_merge_copy_into\ diff --git a/src/modules/punk/mix/commandset/layout-buildversion.txt b/src/modules/punk/mix/commandset/layout-buildversion.txt index 91577416..6b561d48 100644 --- a/src/modules/punk/mix/commandset/layout-buildversion.txt +++ b/src/modules/punk/mix/commandset/layout-buildversion.txt @@ -1,6 +1,7 @@ -0.2.0 +0.3.0 #First line must be a semantic version number #all other lines are ignored. +#0.3.0 - G-012: inert VCS-config payload materialization. New lib::layout_materialize_renames (public map of inert->materialized tail names, initially {gitignore.in .gitignore}); layout_stage_chain renames inert payloads to live names after composing all layers (new materialized key in its return dict; .anti markers keep targeting store names); layout_materialize withholds the in-place fast path from folders carrying inert payloads so the rename only ever happens in staging. New private helpers lib::_find_inert_payload_relpaths and lib::_apply_materialize_renames. #0.2.0 - G-087 stage 4: overlay merge primitive in lib - layout_materialize (entry point returning the effective content folder; fast path returns the store folder untouched for single-source chains with no .anti markers), layout_resolve_chain (vendor-then-custom tier chain with @ derived-layout expansion, cycle-guarded), layout_stage_chain (staging-dir composition applying .anti deletion markers; #layout_staging marker guards against clobbering non-staging dirs), plus private helpers _dir_entries/_find_anti_relpaths/_merge_copy_into. The _project pseudo-vendor participates in no chain (retired for layouts - G-087 stage 5 decision). #0.2.0 - new lib::layoutfolder_scan_for_template_files (path-based core of layout_scan_for_template_files); layout_scan_for_template_files, layout_all_files and templatefiles.relative now operate on the overlay-materialized content rather than the primary store folder only (the staging marker file is excluded from listings/scans). #0.1.1 - fix: no-handler warning paths in collection::references_as_dict and lib::layouts_dict used 'put' instead of 'puts' and then errored on an unset dict variable; they now warn correctly and return an empty dict. references_as_dict warning message no longer misattributes itself to layouts_dict. diff --git a/src/project_layouts/README.md b/src/project_layouts/README.md index 89fe24e7..cdac0493 100644 --- a/src/project_layouts/README.md +++ b/src/project_layouts/README.md @@ -121,11 +121,36 @@ folders by punk::mix::commandset::layout::lib::layout_materialize (used by in src/decktemplates/custom/punk/layout_refs/) for a working example of custom-over-vendor override, a .anti deletion and derivation; semantics detail in custom/punk/sample-0.1/extra.txt. -- Chains of one folder with no .anti markers (e.g the thin punk.project - layout, module-carried layouts) are used in place - no copying. Anything - else is composed into a disposable staging directory (deterministic - per-layout path under the system temp dir, marked with a #layout_staging - file) which project.new removes after use. +- Chains of one folder with no .anti markers and no inert VCS-config payloads + (below) are used in place - no copying. Anything else is composed into a + disposable staging directory (deterministic per-layout path under the system + temp dir, marked with a #layout_staging file) which project.new removes after use. + +Inert VCS-config payloads (G-012) +--------------------------------- + +A payload file that would be LIVE VCS configuration under its real name must +never be stored under that name in a layout: git treats any `.gitignore` +anywhere in the tree as live config for its subtree, so a literal `.gitignore` +payload self-censors the layout in the punkshell repo (and any file the +payload ignores silently drops out of git tracking - the G-012 hazard). + +- Payloads are stored under an inert tail name and materialized to the live + name when the layout's effective content is composed: `gitignore.in` becomes + `.gitignore` in the staging dir (never in the store). The rename map lives + in `punk::mix::commandset::layout::lib::layout_materialize_renames` and is + the extension point for future live-config payload classes. +- The rename runs after every overlay layer is composed, so `.anti` markers + always target STORE names: use `gitignore.in.anti` to delete an inherited + payload, never `.gitignore.anti`. +- A layout carrying both the inert and the materialized name at the same + location is contradictory and errors at materialization. +- `.fossil-settings/` payloads need no such treatment: fossil reads them only + at a checkout root, so they are inert in the store by nature. +- The vendor/punk `gitignore.in` payloads are DERIVED mirrors of the punkshell + root `.gitignore`, refreshed (punkcheck-tracked) by the make.tcl thin-layout + sync step. Edit the root `.gitignore` and rebuild (`make.tcl + modules`/`libs`/`packages`/`bakehouse`); never hand-edit the payloads. Store structure --------------- diff --git a/src/project_layouts/custom/punk/othersample@sample-0.1/README.md b/src/project_layouts/custom/punk/othersample@sample-0.1/README.md index 59c326f7..8a6469ff 100644 --- a/src/project_layouts/custom/punk/othersample@sample-0.1/README.md +++ b/src/project_layouts/custom/punk/othersample@sample-0.1/README.md @@ -12,10 +12,11 @@ sample-0.1 (vendor/punk/sample-0.1 merged with custom/punk/sample-0.1), with this folder's own content applied on top. This README overrides the one inherited from the sample-0.1 chain, and the -zero-byte .gitignore.anti marker beside it deletes the .gitignore inherited -from vendor/punk/sample-0.1 - so a project generated from punk.othersample -contains this README, extra.txt from custom/punk/sample-0.1, and no -.gitignore. +zero-byte gitignore.in.anti marker beside it deletes the gitignore.in payload +inherited from vendor/punk/sample-0.1 - so a project generated from +punk.othersample contains this README, extra.txt from custom/punk/sample-0.1, +and no .gitignore. (The .gitignore payload is stored inert as gitignore.in - +G-012 - and .anti markers target store names.) See custom/punk/sample-0.1/extra.txt for the full overlay/merge semantics. diff --git a/src/project_layouts/custom/punk/othersample@sample-0.1/.gitignore.anti b/src/project_layouts/custom/punk/othersample@sample-0.1/gitignore.in.anti similarity index 100% rename from src/project_layouts/custom/punk/othersample@sample-0.1/.gitignore.anti rename to src/project_layouts/custom/punk/othersample@sample-0.1/gitignore.in.anti diff --git a/src/project_layouts/custom/punk/sample-0.1/extra.txt b/src/project_layouts/custom/punk/sample-0.1/extra.txt index 0ab7a25e..1d9d875b 100644 --- a/src/project_layouts/custom/punk/sample-0.1/extra.txt +++ b/src/project_layouts/custom/punk/sample-0.1/extra.txt @@ -29,5 +29,17 @@ Derived layouts: a working example (it also demonstrates a .anti deletion). Composition happens in a disposable staging directory at generation time - the store folders -are never modified, and a layout whose chain is a single folder with no .anti markers is used -in place without any copying. +are never modified, and a layout whose chain is a single folder with no .anti markers and no +inert VCS-config payloads (below) is used in place without any copying. + +Inert VCS-config payloads (G-012): +- A payload that would be LIVE VCS configuration under its real name is stored under an + inert name and materialized at generation: gitignore.in is renamed to .gitignore in the + composed staging dir (never in the store) by layout_materialize. Never store a literal + .gitignore in a layout - git would treat it as live config for the layout tree itself in + the punkshell repo (the self-censoring-template hazard G-012 exists to fix). +- .anti markers target STORE names: name gitignore.in.anti to delete an inherited + gitignore.in payload (see ../othersample@sample-0.1), never .gitignore.anti. +- The vendor/punk layouts' gitignore.in payloads are derived mirrors of the punkshell root + .gitignore, refreshed (punkcheck-tracked) by the make.tcl thin-layout sync step - edit the + root .gitignore, not the payloads. diff --git a/src/project_layouts/vendor/punk/basic/.gitignore b/src/project_layouts/vendor/punk/basic/.gitignore deleted file mode 100644 index 4d6b6912..00000000 --- a/src/project_layouts/vendor/punk/basic/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ - -/bin/ -/lib/ -#The directory for compiled/built Tcl modules -/modules/ -/vendorbuilds/ - -#Temporary files e.g from tests -/tmp/ - -/logs/ -**/_aside/ -**/_build/ -scratch* - -#Built documentation -/html/ -/man/ -/md/ -/doc/ - -/test* - - -#Built tclkits (if any) -punk*.exe -tcl*.exe - -#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) -_FOSSIL_ -.fos -.fslckout -*.fossil - -#miscellaneous editor files etc -*.swp - - -todo.txt - -zig-cache/ -zig-out/ -/release/ -/debug/ -/build/ -/build-*/ -/docgen_tmp/ diff --git a/src/project_layouts/vendor/punk/basic/gitignore.in b/src/project_layouts/vendor/punk/basic/gitignore.in new file mode 100644 index 00000000..79773aaa --- /dev/null +++ b/src/project_layouts/vendor/punk/basic/gitignore.in @@ -0,0 +1,108 @@ + +#while bin is primarily an output - some items here are for bootstrapping - so while they aren't the source - we install and source-control them. +/bin/* +!/bin/AGENTS.md +!/bin/*.cmd +!/bin/*.kit +!/bin/*.tcl +!/bin/*.sh +!/bin/*.bash + + +#The directories for compiled/built Tcl packages (libs and modules) +#These are purely 'output' folders - no need to track +/lib/ +/lib_tcl8/ +/lib_tcl9/ +/modules/ +/modules_tcl8/ +/modules_tcl9/ + +#Temporary files e.g from tests +/tmp/ + +.vscode +#claude harness config: track the shared project settings (hooks/permissions) and project skills, +#ignore everything else (session-local settings etc) +.claude/* +!.claude/settings.json +!.claude/skills/ +.omo + +/logs/ +**/_aside/ +**/_build/ +scratch* + +#Built documentation +/html/ +/man/ +/md/ +/doc/ + +/test* +/src/testdata +/src/scriptapps/test_* + +#G-115 demonstration kit payload - materialized from the src/vfs/punkdeclare.vfs.toml +#declaration (vendor tree + consent-gated bin/packages tier); reproducing it from the +#declaration is the point, so it is never committed +/src/vfs/punkdeclare.vfs/lib_tcl9/ + +#G-127 per-platform payload staging - materialized from %platform% entries in +#src/vfs/.vfs.toml (one subtree per consuming kit target) and selected into +#each kit's merged image at bake time; regenerable staging, never committed +/src/vfs/*.vfs/_targets/ + +#review +/src/docgen + +#local developer notes +/localdoc/ + +#Built tclkits (if any) +*.exe + + +#subfolder for temporary reference files - not source controlled +#we may use git clone to get a copy of the reference files - but we don't want to track them in the repo +TEMP_REFERENCE + +#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) +_FOSSIL_ +.fos +.fslckout +*.fossil + +#fossil-generated checkout artifacts - regenerated on every fossil checkin/checkout per the +#versioned 'manifest' setting (value 'rut'); fossil auto-manages them and they must not be +#git-tracked. Anchored: nested manifest-named files elsewhere are real content. +#See .fossil-settings/AGENTS.md for the git+fossil coexistence contract. +/manifest +/manifest.uuid +/manifest.tags + +#miscellaneous editor files etc +*.swp +*.log + +*.punkcheck + +todo.txt + +zig-cache/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +/~/ + +#Node +/node_modules/ +/package-lock.json +/package.json diff --git a/src/project_layouts/vendor/punk/basic/src/make.tcl b/src/project_layouts/vendor/punk/basic/src/make.tcl index 7699d3e3..8df9a39c 100644 --- a/src/project_layouts/vendor/punk/basic/src/make.tcl +++ b/src/project_layouts/vendor/punk/basic/src/make.tcl @@ -2674,7 +2674,8 @@ RELEASE SEQUENCE (the developer order that satisfies the staleness + provenance (7) build tclsh src/make.tcl vfscommonupdate -confirm 0 (8) build tclsh src/make.tcl bake -confirm 0 kits; close running kit shells first [K5] (9) commit tracked build outputs src/bootsupport, thin-layout script/ - manifest copies (src/project_layouts + + manifest/gitignore.in payload copies + (src/project_layouts + templates modpod payload), src/vfs/_vfscommon.vfs @@ -2712,9 +2713,11 @@ DIAGRAM 1 - DATA FLOW: SOURCE -> BUILT PACKAGES -> PROPAGATION TARGETS DIAGRAM 1b - THIN-LAYOUT SYNC (part of modules/libs/packages/bakehouse runs) ---------------------------------------------------------------------------- - src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config + .gitignore src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config | - | punkcheck-recorded copies into each vendor layout carrying src/make.tcl + | punkcheck-recorded copies: root .gitignore -> every vendor layout's inert + | gitignore.in payload (G-012; materialized to .gitignore at generation), + | scripts/manifests -> each vendor layout carrying src/make.tcl v src/project_layouts/vendor/punk//src/... (thin layouts: scripts, docs, | manifests - no module snapshots) @@ -6634,9 +6637,11 @@ if {$::punkboot::command in {bakehouse packages libs}} { if {$::punkboot::command in {bakehouse packages modules libs}} { ######################################################## #templates - thin-layout sync (G-087 stage 3; see DIAGRAM 1b in ::punkboot::workflow_text) - #sync boot scripts (build.tcl, make.tcl) and bootsupport include_modules.config manifests into the - #thin vendor layouts (those that carry src/make.tcl), then sync the punk.project layout payload from - #the store into the punk::mix::templates modpod source tree so the built module ships it. + #sync the canonical root .gitignore into every vendor layout as the inert gitignore.in + #payload (G-012 - materialized to .gitignore at project generation), sync boot scripts + #(build.tcl, make.tcl) and bootsupport include_modules.config manifests into the thin + #layouts that carry src/make.tcl, then sync the punk.project layout payload from the + #store into the punk::mix::templates modpod source tree so the built module ships it. #Layouts store no bootsupport/vfs module snapshots - 'dev project.new' injects bootsupport into #generated projects from the generating shell at generation time. set layout_bases [list {*}{ @@ -6650,10 +6655,6 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { } set project_layouts [glob -nocomplain -dir $layoutbase -type d -tail *] foreach layoutname $project_layouts { - if {![file exists $layoutbase/$layoutname/src/make.tcl]} { - #layout doesn't carry boot scripts (e.g minimal, sample-0.1) - nothing to sync - continue - } set config [dict create {*}{ -make-step sync_layouts }] @@ -6662,16 +6663,27 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { $tpl_installer set_source_target $sourcefolder $layoutbase/$layoutname set tpl_event [$tpl_installer start_event $config] #---------- + #G-012: every layout's gitignore payload is a derived mirror of the canonical root + #.gitignore, stored inert as gitignore.in (materialized to .gitignore in the + #generated project by punk::mix::commandset::layout::lib::layout_materialize). + #Canonical source is the REPO root .gitignore ($projectroot, not $sourcefolder). set pairs [list {*}{ - } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ - } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } [list $projectroot/.gitignore $layoutbase/$layoutname/gitignore.in] {*}{ } ] - #bootsupport manifests: sync only into bootsupport modules folders the layout already carries - foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { - set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config - if {[file exists $src_manifest]} { - lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + if {[file exists $layoutbase/$layoutname/src/make.tcl]} { + #layout carries boot scripts - sync them too (layouts that don't, e.g minimal, + #sample-0.1, receive only the gitignore payload) + lappend pairs {*}{ + } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ + } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } + #bootsupport manifests: sync only into bootsupport modules folders the layout already carries + foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { + set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config + if {[file exists $src_manifest]} { + lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + } } } diff --git a/src/project_layouts/vendor/punk/minimal/.gitignore b/src/project_layouts/vendor/punk/minimal/.gitignore deleted file mode 100644 index deddaf71..00000000 --- a/src/project_layouts/vendor/punk/minimal/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ - -/bin/ -/lib/ -#The directory for compiled/built Tcl modules -/modules/ -/vendorbuilds/ - -#Temporary files e.g from tests -/tmp/ - -/logs/ -**/_aside/ -**/_build/ -scratch* - -#Built documentation -/html/ -/man/ -/md/ -/doc/ - -/test* - - -#Built tclkits (if any) -punk*.exe -tcl*.exe - -#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) -_FOSSIL_ -.fos -.fslckout -*.fossil - -#miscellaneous editor files etc -*.swp - - -todo.txt diff --git a/src/project_layouts/vendor/punk/minimal/gitignore.in b/src/project_layouts/vendor/punk/minimal/gitignore.in new file mode 100644 index 00000000..79773aaa --- /dev/null +++ b/src/project_layouts/vendor/punk/minimal/gitignore.in @@ -0,0 +1,108 @@ + +#while bin is primarily an output - some items here are for bootstrapping - so while they aren't the source - we install and source-control them. +/bin/* +!/bin/AGENTS.md +!/bin/*.cmd +!/bin/*.kit +!/bin/*.tcl +!/bin/*.sh +!/bin/*.bash + + +#The directories for compiled/built Tcl packages (libs and modules) +#These are purely 'output' folders - no need to track +/lib/ +/lib_tcl8/ +/lib_tcl9/ +/modules/ +/modules_tcl8/ +/modules_tcl9/ + +#Temporary files e.g from tests +/tmp/ + +.vscode +#claude harness config: track the shared project settings (hooks/permissions) and project skills, +#ignore everything else (session-local settings etc) +.claude/* +!.claude/settings.json +!.claude/skills/ +.omo + +/logs/ +**/_aside/ +**/_build/ +scratch* + +#Built documentation +/html/ +/man/ +/md/ +/doc/ + +/test* +/src/testdata +/src/scriptapps/test_* + +#G-115 demonstration kit payload - materialized from the src/vfs/punkdeclare.vfs.toml +#declaration (vendor tree + consent-gated bin/packages tier); reproducing it from the +#declaration is the point, so it is never committed +/src/vfs/punkdeclare.vfs/lib_tcl9/ + +#G-127 per-platform payload staging - materialized from %platform% entries in +#src/vfs/.vfs.toml (one subtree per consuming kit target) and selected into +#each kit's merged image at bake time; regenerable staging, never committed +/src/vfs/*.vfs/_targets/ + +#review +/src/docgen + +#local developer notes +/localdoc/ + +#Built tclkits (if any) +*.exe + + +#subfolder for temporary reference files - not source controlled +#we may use git clone to get a copy of the reference files - but we don't want to track them in the repo +TEMP_REFERENCE + +#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) +_FOSSIL_ +.fos +.fslckout +*.fossil + +#fossil-generated checkout artifacts - regenerated on every fossil checkin/checkout per the +#versioned 'manifest' setting (value 'rut'); fossil auto-manages them and they must not be +#git-tracked. Anchored: nested manifest-named files elsewhere are real content. +#See .fossil-settings/AGENTS.md for the git+fossil coexistence contract. +/manifest +/manifest.uuid +/manifest.tags + +#miscellaneous editor files etc +*.swp +*.log + +*.punkcheck + +todo.txt + +zig-cache/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +/~/ + +#Node +/node_modules/ +/package-lock.json +/package.json diff --git a/src/project_layouts/vendor/punk/project-0.1/.gitignore b/src/project_layouts/vendor/punk/project-0.1/.gitignore deleted file mode 100644 index e1889f93..00000000 --- a/src/project_layouts/vendor/punk/project-0.1/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ - -/bin/* -!/bin/*.cmd -!/bin/*.kit -!/bin/*.tcl -!/bin/*.sh -!/bin/*.bash -/lib/ -#The directory for compiled/built Tcl modules -/modules/ -/vendorbuilds/ - -#Temporary files e.g from tests -/tmp/ - -/logs/ -**/_aside/ -**/_build/ -scratch* - -#Built documentation -/html/ -/man/ -/md/ -/doc/ - -/test* - - -#Built tclkits (if any) -*.exe - -#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) -_FOSSIL_ -.fos -.fslckout -*.fossil - -#miscellaneous editor files etc -*.swp -*.log - -*.punkcheck - -todo.txt - -zig-cache/ -zig-out/ -/release/ -/debug/ -/build/ -/build-*/ -/docgen_tmp/ diff --git a/src/project_layouts/vendor/punk/project-0.1/gitignore.in b/src/project_layouts/vendor/punk/project-0.1/gitignore.in new file mode 100644 index 00000000..79773aaa --- /dev/null +++ b/src/project_layouts/vendor/punk/project-0.1/gitignore.in @@ -0,0 +1,108 @@ + +#while bin is primarily an output - some items here are for bootstrapping - so while they aren't the source - we install and source-control them. +/bin/* +!/bin/AGENTS.md +!/bin/*.cmd +!/bin/*.kit +!/bin/*.tcl +!/bin/*.sh +!/bin/*.bash + + +#The directories for compiled/built Tcl packages (libs and modules) +#These are purely 'output' folders - no need to track +/lib/ +/lib_tcl8/ +/lib_tcl9/ +/modules/ +/modules_tcl8/ +/modules_tcl9/ + +#Temporary files e.g from tests +/tmp/ + +.vscode +#claude harness config: track the shared project settings (hooks/permissions) and project skills, +#ignore everything else (session-local settings etc) +.claude/* +!.claude/settings.json +!.claude/skills/ +.omo + +/logs/ +**/_aside/ +**/_build/ +scratch* + +#Built documentation +/html/ +/man/ +/md/ +/doc/ + +/test* +/src/testdata +/src/scriptapps/test_* + +#G-115 demonstration kit payload - materialized from the src/vfs/punkdeclare.vfs.toml +#declaration (vendor tree + consent-gated bin/packages tier); reproducing it from the +#declaration is the point, so it is never committed +/src/vfs/punkdeclare.vfs/lib_tcl9/ + +#G-127 per-platform payload staging - materialized from %platform% entries in +#src/vfs/.vfs.toml (one subtree per consuming kit target) and selected into +#each kit's merged image at bake time; regenerable staging, never committed +/src/vfs/*.vfs/_targets/ + +#review +/src/docgen + +#local developer notes +/localdoc/ + +#Built tclkits (if any) +*.exe + + +#subfolder for temporary reference files - not source controlled +#we may use git clone to get a copy of the reference files - but we don't want to track them in the repo +TEMP_REFERENCE + +#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) +_FOSSIL_ +.fos +.fslckout +*.fossil + +#fossil-generated checkout artifacts - regenerated on every fossil checkin/checkout per the +#versioned 'manifest' setting (value 'rut'); fossil auto-manages them and they must not be +#git-tracked. Anchored: nested manifest-named files elsewhere are real content. +#See .fossil-settings/AGENTS.md for the git+fossil coexistence contract. +/manifest +/manifest.uuid +/manifest.tags + +#miscellaneous editor files etc +*.swp +*.log + +*.punkcheck + +todo.txt + +zig-cache/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +/~/ + +#Node +/node_modules/ +/package-lock.json +/package.json diff --git a/src/project_layouts/vendor/punk/project-0.1/src/make.tcl b/src/project_layouts/vendor/punk/project-0.1/src/make.tcl index 7699d3e3..8df9a39c 100644 --- a/src/project_layouts/vendor/punk/project-0.1/src/make.tcl +++ b/src/project_layouts/vendor/punk/project-0.1/src/make.tcl @@ -2674,7 +2674,8 @@ RELEASE SEQUENCE (the developer order that satisfies the staleness + provenance (7) build tclsh src/make.tcl vfscommonupdate -confirm 0 (8) build tclsh src/make.tcl bake -confirm 0 kits; close running kit shells first [K5] (9) commit tracked build outputs src/bootsupport, thin-layout script/ - manifest copies (src/project_layouts + + manifest/gitignore.in payload copies + (src/project_layouts + templates modpod payload), src/vfs/_vfscommon.vfs @@ -2712,9 +2713,11 @@ DIAGRAM 1 - DATA FLOW: SOURCE -> BUILT PACKAGES -> PROPAGATION TARGETS DIAGRAM 1b - THIN-LAYOUT SYNC (part of modules/libs/packages/bakehouse runs) ---------------------------------------------------------------------------- - src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config + .gitignore src/make.tcl src/build.tcl src/bootsupport/modules*/include_modules.config | - | punkcheck-recorded copies into each vendor layout carrying src/make.tcl + | punkcheck-recorded copies: root .gitignore -> every vendor layout's inert + | gitignore.in payload (G-012; materialized to .gitignore at generation), + | scripts/manifests -> each vendor layout carrying src/make.tcl v src/project_layouts/vendor/punk//src/... (thin layouts: scripts, docs, | manifests - no module snapshots) @@ -6634,9 +6637,11 @@ if {$::punkboot::command in {bakehouse packages libs}} { if {$::punkboot::command in {bakehouse packages modules libs}} { ######################################################## #templates - thin-layout sync (G-087 stage 3; see DIAGRAM 1b in ::punkboot::workflow_text) - #sync boot scripts (build.tcl, make.tcl) and bootsupport include_modules.config manifests into the - #thin vendor layouts (those that carry src/make.tcl), then sync the punk.project layout payload from - #the store into the punk::mix::templates modpod source tree so the built module ships it. + #sync the canonical root .gitignore into every vendor layout as the inert gitignore.in + #payload (G-012 - materialized to .gitignore at project generation), sync boot scripts + #(build.tcl, make.tcl) and bootsupport include_modules.config manifests into the thin + #layouts that carry src/make.tcl, then sync the punk.project layout payload from the + #store into the punk::mix::templates modpod source tree so the built module ships it. #Layouts store no bootsupport/vfs module snapshots - 'dev project.new' injects bootsupport into #generated projects from the generating shell at generation time. set layout_bases [list {*}{ @@ -6650,10 +6655,6 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { } set project_layouts [glob -nocomplain -dir $layoutbase -type d -tail *] foreach layoutname $project_layouts { - if {![file exists $layoutbase/$layoutname/src/make.tcl]} { - #layout doesn't carry boot scripts (e.g minimal, sample-0.1) - nothing to sync - continue - } set config [dict create {*}{ -make-step sync_layouts }] @@ -6662,16 +6663,27 @@ if {$::punkboot::command in {bakehouse packages modules libs}} { $tpl_installer set_source_target $sourcefolder $layoutbase/$layoutname set tpl_event [$tpl_installer start_event $config] #---------- + #G-012: every layout's gitignore payload is a derived mirror of the canonical root + #.gitignore, stored inert as gitignore.in (materialized to .gitignore in the + #generated project by punk::mix::commandset::layout::lib::layout_materialize). + #Canonical source is the REPO root .gitignore ($projectroot, not $sourcefolder). set pairs [list {*}{ - } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ - } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } [list $projectroot/.gitignore $layoutbase/$layoutname/gitignore.in] {*}{ } ] - #bootsupport manifests: sync only into bootsupport modules folders the layout already carries - foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { - set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config - if {[file exists $src_manifest]} { - lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + if {[file exists $layoutbase/$layoutname/src/make.tcl]} { + #layout carries boot scripts - sync them too (layouts that don't, e.g minimal, + #sample-0.1, receive only the gitignore payload) + lappend pairs {*}{ + } [list $sourcefolder/build.tcl $layoutbase/$layoutname/src/build.tcl] {*}{ + } [list $sourcefolder/make.tcl $layoutbase/$layoutname/src/make.tcl] {*}{ + } + #bootsupport manifests: sync only into bootsupport modules folders the layout already carries + foreach bm [glob -nocomplain -dir $layoutbase/$layoutname/src/bootsupport -type d -tails modules modules_tcl*] { + set src_manifest $sourcefolder/bootsupport/$bm/include_modules.config + if {[file exists $src_manifest]} { + lappend pairs [list $src_manifest $layoutbase/$layoutname/src/bootsupport/$bm/include_modules.config] + } } } diff --git a/src/project_layouts/vendor/punk/sample-0.1/.gitignore b/src/project_layouts/vendor/punk/sample-0.1/.gitignore deleted file mode 100644 index 4d6b6912..00000000 --- a/src/project_layouts/vendor/punk/sample-0.1/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ - -/bin/ -/lib/ -#The directory for compiled/built Tcl modules -/modules/ -/vendorbuilds/ - -#Temporary files e.g from tests -/tmp/ - -/logs/ -**/_aside/ -**/_build/ -scratch* - -#Built documentation -/html/ -/man/ -/md/ -/doc/ - -/test* - - -#Built tclkits (if any) -punk*.exe -tcl*.exe - -#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) -_FOSSIL_ -.fos -.fslckout -*.fossil - -#miscellaneous editor files etc -*.swp - - -todo.txt - -zig-cache/ -zig-out/ -/release/ -/debug/ -/build/ -/build-*/ -/docgen_tmp/ diff --git a/src/project_layouts/vendor/punk/sample-0.1/gitignore.in b/src/project_layouts/vendor/punk/sample-0.1/gitignore.in new file mode 100644 index 00000000..79773aaa --- /dev/null +++ b/src/project_layouts/vendor/punk/sample-0.1/gitignore.in @@ -0,0 +1,108 @@ + +#while bin is primarily an output - some items here are for bootstrapping - so while they aren't the source - we install and source-control them. +/bin/* +!/bin/AGENTS.md +!/bin/*.cmd +!/bin/*.kit +!/bin/*.tcl +!/bin/*.sh +!/bin/*.bash + + +#The directories for compiled/built Tcl packages (libs and modules) +#These are purely 'output' folders - no need to track +/lib/ +/lib_tcl8/ +/lib_tcl9/ +/modules/ +/modules_tcl8/ +/modules_tcl9/ + +#Temporary files e.g from tests +/tmp/ + +.vscode +#claude harness config: track the shared project settings (hooks/permissions) and project skills, +#ignore everything else (session-local settings etc) +.claude/* +!.claude/settings.json +!.claude/skills/ +.omo + +/logs/ +**/_aside/ +**/_build/ +scratch* + +#Built documentation +/html/ +/man/ +/md/ +/doc/ + +/test* +/src/testdata +/src/scriptapps/test_* + +#G-115 demonstration kit payload - materialized from the src/vfs/punkdeclare.vfs.toml +#declaration (vendor tree + consent-gated bin/packages tier); reproducing it from the +#declaration is the point, so it is never committed +/src/vfs/punkdeclare.vfs/lib_tcl9/ + +#G-127 per-platform payload staging - materialized from %platform% entries in +#src/vfs/.vfs.toml (one subtree per consuming kit target) and selected into +#each kit's merged image at bake time; regenerable staging, never committed +/src/vfs/*.vfs/_targets/ + +#review +/src/docgen + +#local developer notes +/localdoc/ + +#Built tclkits (if any) +*.exe + + +#subfolder for temporary reference files - not source controlled +#we may use git clone to get a copy of the reference files - but we don't want to track them in the repo +TEMP_REFERENCE + +#ignore fossil database files (but keep .fossil-settings and .fossil-custom in repository even if fossil not being used at your site) +_FOSSIL_ +.fos +.fslckout +*.fossil + +#fossil-generated checkout artifacts - regenerated on every fossil checkin/checkout per the +#versioned 'manifest' setting (value 'rut'); fossil auto-manages them and they must not be +#git-tracked. Anchored: nested manifest-named files elsewhere are real content. +#See .fossil-settings/AGENTS.md for the git+fossil coexistence contract. +/manifest +/manifest.uuid +/manifest.tags + +#miscellaneous editor files etc +*.swp +*.log + +*.punkcheck + +todo.txt + +zig-cache/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +/~/ + +#Node +/node_modules/ +/package-lock.json +/package.json diff --git a/src/tests/modules/punk/mix/testsuites/layout/materialize.test b/src/tests/modules/punk/mix/testsuites/layout/materialize.test index 238198aa..c1b76bb7 100644 --- a/src/tests/modules/punk/mix/testsuites/layout/materialize.test +++ b/src/tests/modules/punk/mix/testsuites/layout/materialize.test @@ -8,6 +8,9 @@ package require punk::mix::commandset::layout #is fed -layoutinfo directly). The repo fixtures (vendor/custom punk/sample-0.1 + #othersample@sample-0.1) are exercised end-to-end via dev project.new - see the G-087 detail #file verification records. +#extended 2026-08-01 (agent, G-012) - inert VCS-config payloads: the gitignore.in -> .gitignore +#materialize rename (map, any-depth staging rename, store-name .anti targeting, inert+live +#conflict error, fast-path denial so the store is never renamed). namespace eval ::testspace { namespace import ::tcltest::* @@ -362,6 +365,89 @@ namespace eval ::testspace { -cleanup {}\ -result [list 1 3 derived-readme extra modules-readme 0 .gitignore] + # -- --- --- G-012 inert VCS-config payloads --- --- -- + + #added 2026-08-01 (agent, G-012) - inert-payload rename map and staging materialization pins + test materialize_renames_map {layout_materialize_renames returns the inert->materialized tail map}\ + -setup $common -body { + punk::mix::commandset::layout::lib::layout_materialize_renames + }\ + -cleanup {}\ + -result {gitignore.in .gitignore} + + #added 2026-08-01 (agent, G-012) + test stage_inert_payload_renamed {inert gitignore.in composes to live .gitignore at any depth}\ + -setup $common -body { + set store [make_store s30] + fwrite $store/vendor/punk/sample/gitignore.in "ignore-payload" + fwrite $store/vendor/punk/sample/sub/gitignore.in "nested-payload" + fwrite $store/vendor/punk/sample/keep.txt "keep" + set chain [punk::mix::commandset::layout::lib::layout_resolve_chain $store punk sample] + set staging [file join $store staging] + set sres [punk::mix::commandset::layout::lib::layout_stage_chain $chain $staging] + lappend result [fread $staging/.gitignore] + lappend result [fread $staging/sub/.gitignore] + lappend result [file exists $staging/gitignore.in] + lappend result [file exists $staging/sub/gitignore.in] + lappend result [lsort [dict get $sres materialized]] + }\ + -cleanup {}\ + -result [list ignore-payload nested-payload 0 0 {{gitignore.in .gitignore} {sub/gitignore.in sub/.gitignore}}] + + #added 2026-08-01 (agent, G-012) + test stage_inert_anti_targets_store_name {gitignore.in.anti deletes the inherited payload; nothing materializes}\ + -setup $common -body { + set store [make_store s31] + fwrite $store/vendor/punk/sample/gitignore.in "ignore-payload" + fwrite $store/vendor/punk/sample/keep.txt "keep" + file mkdir $store/custom/punk/sample + fwrite $store/custom/punk/sample/gitignore.in.anti "" + set chain [punk::mix::commandset::layout::lib::layout_resolve_chain $store punk sample] + set staging [file join $store staging] + set sres [punk::mix::commandset::layout::lib::layout_stage_chain $chain $staging] + lappend result [file exists $staging/.gitignore] + lappend result [file exists $staging/gitignore.in] + lappend result [file exists $staging/keep.txt] + lappend result [dict get $sres deletions] + lappend result [dict get $sres materialized] + }\ + -cleanup {}\ + -result [list 0 0 1 gitignore.in {}] + + #added 2026-08-01 (agent, G-012) + test stage_inert_conflict_errors {a folder carrying both the inert and the materialized name errors}\ + -setup $common -body { + set store [make_store s32] + fwrite $store/vendor/punk/sample/gitignore.in "ignore-payload" + fwrite $store/vendor/punk/sample/.gitignore "live-config" + set chain [punk::mix::commandset::layout::lib::layout_resolve_chain $store punk sample] + set staging [file join $store staging] + set code [catch {punk::mix::commandset::layout::lib::layout_stage_chain $chain $staging} emsg] + lappend result $code + lappend result [string match "*must never be layout store content*" $emsg] + }\ + -cleanup {}\ + -result [list 1 1] + + #added 2026-08-01 (agent, G-012) + test materialize_inert_forces_staging {single-folder chain carrying an inert payload is staged; the store is never renamed}\ + -setup $common -body { + set store [make_store s33] + fwrite $store/vendor/punk/solo/gitignore.in "ignore-payload" + fwrite $store/vendor/punk/solo/a.txt "a" + set linfo [list path [file join $store vendor punk solo] basefolder $store sourceinfo {}] + set staging [file join $store staging] + set mat [punk::mix::commandset::layout::lib::layout_materialize punk.solo -layoutinfo $linfo -stagingdir $staging] + lappend result [dict get $mat staged] + lappend result [expr {[dict get $mat path] ne [file join $store vendor punk solo]}] + lappend result [fread [dict get $mat path]/.gitignore] + lappend result [file exists [file join $store vendor punk solo gitignore.in]] + lappend result [file exists [file join $store vendor punk solo .gitignore]] + lappend result [dict get $mat materialized] + }\ + -cleanup {}\ + -result [list 1 1 ignore-payload 1 0 {{gitignore.in .gitignore}}] + variable BASE file delete -force $BASE