Dashboard › craft › Distillation
Distillation
ID: e70e7e95-71d0-4ff7-9ec0-8a6be51673fd
Generation: 0
Tokens: 2042
R_compression: 24.743
C_norm: 0.000
Archived: No
Created: 2026-07-21 16:41:25
Source IDs:
["049563a83a4a1cda96cc7bb4b6d55198","f54e60576af23daad1154e03e1e636c2"]
Observations
Date: July 21, 2026
- π‘ (16:26) [tool result] Craft "workspaces" (multi-product release) design research completed on branch feat/prefixed-tags. No code written. Key finding: craft assumes one product per config file per invocation β single cached config (_configCache, config.ts:56) and single cached global GitHub config (_globalGitHubConfigCache, config.ts:283).
- π‘ (16:26) [tool result] The term "workspace" already exists in craft codebase but means npm package workspaces (publishing many npm packages from one target, all same version) β NOT independently-versioned products. Precedent: static expand() mechanism at config.ts:577 and npm.ts:179, operates at target-config level with one version.
- π‘ (16:26) [tool result] Intended multi-product model today (per existing plan .craft-issue-842-plan.md:141) is separate .craft.yml per product; a single-file/workspace-selector model does not exist and would require threading a selector through everything.
- π‘ (16:26) [tool result] Config load flow: findConfigFile() walks up from cwd for .craft.yml (config.ts:63-88), caches path in _configPathCache. CONFIG_FILE_NAME = '.craft.yml' (config.ts:41). TODO comment at config.ts:40: "support multiple configuration files (one per configuration)". getConfiguration() reads + validateConfiguration() β CraftProjectConfigSchema.parse β caches _configCache (config.ts:147-161, 125-142). loadConfigurationFromString() is the --config-from variant (config.ts:170-178). getConfigFileDir() = dirname of config path (config.ts:110-116), used as rootDir everywhere. getGlobalGitHubConfig() returns config.github or infers owner/repo from git remote, frozen+cached (config.ts:284-327).
- π‘ (16:26) [tool result] publishMain flow (publish.ts:561): config=getConfiguration() (publish.ts:563); branchPrefix = config.releaseBranchPrefix||'release'; release branch = ${branchPrefix}/${newVersion} (publish.ts:585-601); checkout or findReleaseBranches() fuzzy help on failure (publish.ts:608-637, git.ts:222); revision=git.revparse('HEAD') (publish.ts:641); getStatusProviderFromConfig()/getArtifactProviderFromConfig() (publish.ts:644-645); targetConfigList=expandWorkspaceTargets(config.targets) (publish.ts:672); publish-state file keyed by owner/repo + sha1(cwd) + version (publish.ts:677-716, publishState.ts:78-91); getTargetList() instantiates each target new targetClass(targetConfig, artifactProvider, githubRepo) (publish.ts:260-290); loop publishToTarget()βtarget.publish(version, revision) (publish.ts:757-761); github target write path versionToTag(version, tagPrefix) (github.ts:197,259,618,771; version.ts:135), isLatestRelease()βmake_latest (github.ts:762-864), floating tags (github.ts:652); handleReleaseBranch() merges+deletes branch (publish.ts:421-515); runPostReleaseCommand() (publish.ts:526).
- π‘ (16:26) [tool result] Release-request mechanism (this repo's action.yml, composite "Craft Prepare Release"): runs craft prepare (action.yml:157-182), then craft targets (:184-196), then "Request publish" (:198-333). Builds issue title = "publish: ${GITHUB_REPOSITORY}${SUBDIRECTORY}@${RESOLVED_VERSION}" (action.yml:241), SUBDIRECTORY=inputs.path when not '.' (:211). PUBLISH_REPO = inputs.publish_repo || {owner}/publish (:213); "self" β $GITHUB_REPOSITORY (:216-218), documented in README:126 and github-actions.md:48. Finds existing issue by exact title match (:247), preserves checked target boxes (:257-285), rebuilds body with "### Targets" checklist (:312-316) and changelog (:288-300). Body states: "Assign the accepted label to this issue to approve the release." (:310).
- π‘ (16:26) [tool result] Schema findings: top-level CraftProjectConfigSchema is a plain z.object and NOT .passthrough() (schemas/project_config.ts:170-191) β unknown top-level keys stripped by Zod on parse (config.ts:130), so a new top-level products:/workspaces: key must be added to schema explicitly, cannot be smuggled via passthrough. TargetConfigSchema IS .passthrough() (project_config.ts:54-61) β target-specific fields (tagPrefix, workspaces, deployType) flow through freely; TypedTargetConfig<T> (:76-77) is the narrowing pattern. Nested provider schemas use z.record(z.any()) for config (BaseStatusProviderSchema :82-85, BaseArtifactProviderSchema :92-95) β permissive. Existing structured sub-configs to model after: VersioningConfigSchema (:148-151) with nested CalVerConfigSchema (:131-141), ChangelogConfigSchema union (:158-165). A products/workspaces array-of-objects (each with own github, targets, tagPrefix, releaseBranchPrefix, changelog, versioning) would follow this pattern, resolved by new selector-aware getConfiguration(workspace) layer. validateConfiguration error formatting (config.ts:125-142) and checkMinimalConfigVersion (config.ts:186) run on whole config β a products model needs minVersion gating (like auto-version's AUTO_VERSION_MIN_VERSION='2.14.0', config.ts:249).
- π‘ (16:26) Assistant analysis: since "workspace" term is already taken by npm-package workspaces (src/utils/workspaces.ts, expandWorkspaceTargets, config.workspaces, NpmTarget.expand β all publish at same version), a multi-product feature needs a different term, e.g. products, packages, or releaseGroups, to avoid collision.
- π‘ (16:26) Assistant analysis: publish-issue/publish_repo pipeline disambiguates products only by version + subdirectory path; a single top-level file with a selector would collide on issue title (action.yml:241), craft targets checklist, and publish-state key (publishState.ts:87) β this matches BYK's reviewer concern about the "publish" repo. Making single-file multi-product work correctly requires threading a product identifier through the action layer too, not just TS code.
- π‘ (16:26) Assistant stated conclusion: given the scope, this is a design-first effort, not something to implement inside PR #844. Plans to write a proper design doc and decide separately what to do with PR #844 itself (which has real bot/reviewer fixes flagged that shouldn't be lost). Next step: check for an existing follow-up issue and review .craft-issue-842-plan.md to place the design work correctly.