prometeu-studio/docs/packer/agendas/Pack Wizard Studio Decision Propagation Agenda.md
2026-03-24 13:42:55 +00:00

296 lines
14 KiB
Markdown

# Pack Wizard Studio Decision Propagation Agenda
Status: Open
Domain Owner: `docs/packer`
Cross-Domain Impact: `docs/studio`
## Purpose
Converge the packer-side discussion that still remains open after the first `Pack Wizard` propagation wave: the actual `packing` operation.
`summary` and `validation` are already closed enough to implement and consume.
What is still unresolved is how `pack execution` should behave as a packer-owned operation when Studio enters the `Packing` and `Result` phases.
This agenda is therefore about execution semantics, artifact emission, progress visibility, and failure boundaries for `packWorkspace(...)`.
## Problem
The repository already closed the Studio shell boundary and the packer-side preflight boundary, but the actual pack execution contract is still underspecified.
Today the gap is concrete:
1. Studio already depends on a four-phase wizard:
`Summary`, `Validation`, `Packing`, `Result`;
2. the public packer API already exposes `packWorkspace(...)`;
3. `prometeu-packer-v1` still throws `UnsupportedOperationException` for that operation;
4. the specs define `assets.pa` authority and deterministic ordering, but they do not yet define the operational semantics for emitting that artifact through the Studio-facing service boundary.
Without this agenda, implementation risks falling into one of these traps:
- a direct file-write implementation that leaks partial artifacts;
- a Studio-visible progress model that is too vague to support the wizard honestly;
- an execution path that does not clearly separate validation failure from emission failure;
- or a result contract that is too poor for the `Result` phase even if the pack technically succeeds.
## Context
The upstream state is now clear enough to isolate the remaining question.
Already closed:
- Studio is a shell over packer-owned semantics:
[`../../studio/decisions/Pack Wizard in Assets Workspace Decision.md`](../../studio/decisions/Pack%20Wizard%20in%20Assets%20Workspace%20Decision.md)
- packer-side `summary` and `validation` contracts are accepted:
[`../decisions/Pack Wizard Summary and Validation Contracts Decision.md`](../decisions/Pack%20Wizard%20Summary%20and%20Validation%20Contracts%20Decision.md)
- runtime artifact authority is already normative:
[`../specs/4. Build Artifacts and Deterministic Packing Specification.md`](../specs/4.%20Build%20Artifacts%20and%20Deterministic%20Packing%20Specification.md)
- event causality and serialized operation rules are already normative:
[`../specs/5. Diagnostics, Operations, and Studio Integration Specification.md`](../specs/5.%20Diagnostics,%20Operations,%20and%20Studio%20Integration%20Specification.md)
Current code context:
- `getPackWorkspaceSummary(...)` already exists in `FileSystemPackerWorkspaceService`;
- `validatePackWorkspace(...)` already exists in `FileSystemPackerWorkspaceService`;
- `packWorkspace(...)` exists in the public API but is not implemented in `prometeu-packer-v1`;
- the current `PackWorkspaceResult` shape is minimal, but the operational meaning of its fields is not fully closed.
That means the current decision gap is no longer about whether packing should exist.
It is about what guarantees `packWorkspace(...)` must provide when it starts emitting runtime-facing artifacts.
## Options
### Option A - Direct in-place pack with minimal lifecycle semantics
Implement `packWorkspace(...)` as one serialized write-lane operation that:
- optionally reruns the validation gate;
- emits `assets.pa` and companion artifacts directly into their final locations;
- publishes a small number of lifecycle events;
- returns one final result DTO with success or failure.
### Option B - Staged pack transaction with explicit lifecycle phases
Implement `packWorkspace(...)` as one serialized packer-owned execution flow with explicit internal phases:
1. gate
2. plan/materialize
3. stage emit
4. commit/promote
5. finalize result
The operation still appears to Studio as one `packWorkspace(...)` call, but the packer gives stronger semantics:
- validation is rechecked at execution start;
- emitted files are staged before final promotion;
- final artifact visibility changes only at commit;
- progress events map to meaningful lifecycle boundaries;
- the final result distinguishes validation, emission, and persistence failure classes.
### Option C - Detached build session abstraction
Introduce a larger `PackSession`-style model or resumable build-session protocol for packing.
Studio would create a session, observe step state, and then explicitly finalize or close it.
## Tradeoffs
- Option A is the smallest implementation step, but it leaves too many failure and visibility rules implicit.
- Option A also makes it easier to leak partially written artifacts into final paths if the process fails mid-pack.
- Option B fits the existing service boundary while still making artifact visibility and progress semantics explicit.
- Option B also aligns well with the current specs:
serialized writes, causal events, deterministic outputs, and packer-owned truth.
- Option B adds some implementation structure, but that structure corresponds to real operational risk and is not ceremonial.
- Option C could become attractive later if the build system needs cancellation, resume, remote workers, or richer host orchestration.
- Option C is too heavy for the current repository state and would introduce a second interaction model before the first one is stable.
## Recommendation
Adopt `Option B`.
The packer should keep `packWorkspace(...)` as a single public service operation, but internally define and honor explicit execution phases with staged emission and an atomic final visibility boundary.
### Execution Boundary Recommendation
`packWorkspace(...)` should be the only first-wave operation that emits build artifacts.
Rules:
- it runs through the packer-owned serialized write lane for the project;
- it evaluates the active pack set as `registered + included in build`;
- it must perform an internal gate check before emitting artifacts, even if Studio already ran `validation`;
- it must freeze the execution input set before materialization begins;
- a failing gate returns a terminal result without creating final artifacts.
This avoids trusting host orchestration timing as if it were a correctness guarantee.
### Frozen Snapshot Recommendation
`packWorkspace(...)` should not pack from live filesystem rereads after execution begins.
Recommended first-wave baseline:
- the packer creates a frozen pack-execution snapshot before materialization starts;
- that frozen snapshot is derived from the current runtime snapshot but enriches build-relevant walk files with in-memory content bytes;
- content bytes are needed only for:
- registered assets included in build;
- artifact files that actually participate in the current build output;
- non-build assets and non-selected artifact files do not need in-memory content in the pack-execution snapshot;
- the current runtime snapshot model should expose file bytes as optional rather than introducing a second snapshot model in the first wave;
- `PackerRuntimeWalkFile` should therefore carry optional content bytes so the packer can freeze build-relevant inputs without forcing all runtime-backed reads to retain content unnecessarily;
- the family walkers may continue to produce full file probes with bytes loaded during probe processing;
- the variation for runtime versus packing should happen when probe results are exported into the runtime walk projection;
- walker materialization must therefore gain clearer execution context/config so build-focused flows can request content bytes intentionally instead of coupling that behavior to every normal read path.
This preserves precision without turning the general runtime snapshot into a blanket in-memory mirror of the workspace.
### Walker Policy Recommendation
The current walker baseline should remain family-oriented and generalist.
Recommended first-wave baseline:
- family walkers continue to discover files relevant to the asset family;
- that family-oriented discovery remains the normal runtime-backed mode;
- packing adds one extra selection layer instead of redefining walker discovery itself;
- the extra selection layer filters the discovered probe results down to the files that actually participate in the current build output;
- the same export layer also decides whether optional content bytes are injected into `PackerRuntimeWalkFile`.
This means the first-wave split should be:
1. family-relevant probe discovery in the walkers;
2. export/materialization policy for runtime projection;
3. packing-specific projection filter over discovered probe results;
4. optional byte injection only when the export policy requests it.
This is intentionally conservative.
It keeps the walkers on known ground and moves the packing-specific behavior into one explicit projection/materialization policy layer.
Recommended config shape:
```java
public record PackerRuntimeMaterializationConfig(
PackerWalkMode mode,
Predicate<PackerProbeResult> projectionFilter) {
public static PackerRuntimeMaterializationConfig runtimeDefault() {
return new PackerRuntimeMaterializationConfig(PackerWalkMode.RUNTIME, probe -> true);
}
public static PackerRuntimeMaterializationConfig packingBuild() {
return new PackerRuntimeMaterializationConfig(
PackerWalkMode.PACKING,
PackerProbePolicies::isIncludedInCurrentBuild);
}
}
```
With this baseline:
- `PackerWalkMode.RUNTIME` means runtime-backed general projection and suppresses optional content bytes during export;
- `PackerWalkMode.PACKING` means packing-focused projection and injects optional content bytes during export;
- `projectionFilter` decides which discovered probe results actually survive into `PackerRuntimeWalkFile`;
- the first-wave packing filter should keep only current-build probe results;
- byte injection behavior is derived from `mode` rather than from a second explicit boolean in the first wave.
### Emission Recommendation
Artifact emission should be staged before promotion into final visible locations.
Recommended first-wave baseline:
- materialize `assets.pa` and companion artifacts in a staging location owned by the packer operation;
- use `build/.staging/<operation-id>/` as the first-wave staging location;
- `<operation-id>` should be one random 20-character alphanumeric identifier;
- if a staging directory collision happens for that identifier, the packer may overwrite that staging directory rather than adding a second collision-resolution protocol in the first wave;
- treat staging output as non-authoritative until commit;
- promote staged files into final `build/` locations only after the operation reaches a coherent success point;
- if emission fails before commit, final artifact locations must remain unchanged from the caller's point of view.
This is the safest baseline for a filesystem-first packer.
It keeps durable visibility aligned with a packer-owned commit boundary rather than with incidental file-write timing.
### Progress Recommendation
Progress should continue to flow through the existing packer event path rather than through a polling-specific result shape.
The first-wave lifecycle should be observable through summaries and progress updates equivalent to:
1. `packing_started`
2. `packing_validating`
3. `packing_materializing`
4. `packing_emitting`
5. `packing_finalizing`
6. terminal success or failure
The exact event kind names can still be finalized in the decision, but the meaning must be explicit enough for Studio to render the `Packing` phase honestly without fake timers or inferred state.
### Result Recommendation
The final `PackWorkspaceResult` should stay compact but semantically explicit.
The primary result summary should expose at least:
- final status;
- whether validation failed or execution actually began;
- canonical build-relative `assets.pa` artifact reference;
- build-relative companion artifact references when emitted;
- total packed asset count;
- elapsed time in milliseconds.
The first-wave `Result` phase in Studio does not need a full build report dump, but it does need enough structure to distinguish successful pack, blocked pack, and failed pack after execution started.
### Failure Recommendation
The packer should distinguish at least three terminal classes:
1. validation gate failure before emission;
2. execution or materialization failure during pack generation;
3. persistence or promotion failure while making artifacts final.
These classes matter because they map directly to the Studio `Result` phase already decided upstream.
### Build Output Recommendation
The packer publication boundary for this flow should remain `build/`.
Recommended first-wave baseline:
- `packWorkspace(...)` publishes final outputs to `build/`;
- the canonical runtime-facing artifact is `build/assets.pa`;
- the baseline companion artifacts are:
- `build/asset_table.json`
- `build/preload.json`
- `build/asset_table_metadata.json`
- a future shipper may consume those packer outputs together with `program.pbx`;
- the shipper is mentioned here only to keep the boundary explicit, not because it participates in `packWorkspace(...)`.
This keeps the current domain boundary intact:
the packer publishes build artifacts and the shipper assembles cartridges.
## Open Questions
None for the first-wave execution shape.
The remaining work is to convert this agenda into a decision and then propagate the agreed materialization policy into code and specs.
## Recommendation Summary
This agenda recommends closing the first-wave `packing` contract as:
1. one packer-owned `packWorkspace(...)` operation;
2. internally phased and serialized through the project write lane;
3. guarded by a packer-owned validation check at execution start;
4. based on one frozen in-memory execution snapshot for the build-relevant asset bytes;
5. staged under `build/.staging/<operation-id>/` before promotion to final artifact visibility in `build/`;
6. observable through causality-preserving progress events;
7. finished with a result that distinguishes blocked, failed, and successful pack outcomes.
## Next Suggested Step
Convert this agenda into a `docs/packer` decision focused on `pack execution` semantics and propagation targets.
That decision should then drive:
1. one PR for `prometeu-packer-api` result and event-contract adjustments, if needed;
2. one PR for `prometeu-packer-v1` execution, staging, and artifact-promotion behavior;
3. one Studio PR to bind the `Packing` and `Result` phases to the final packer-owned execution contract.