Add worktree config section schema and shape validation #320
Labels
No labels
batch
bug
chore
documentation
enhancement
pi-loop
ready
resume
No milestone
No project
No assignees
1 participant
Notifications
Due date
Dependencies
No dependencies set
Reference
david/pi-loop#320
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Add strict schema and shape validation for the new
worktree:section (enabled,dir) inpiloop-config.yaml— the parsing half of making pi-loop's worktree directory configurable (ADR-022). Downstream steps (parse-timedirvalidation, worktree routing, early-fetch gate) all build on this section being parsed.Background
pi-loop is a Node.js/TypeScript orchestrator that runs each issue in a git worktree. Today worktrees are created only for bare repos, with the parent directory hardcoded to
dirname(originalCwd); normal clones run in place. ADR-022 (docs/adr/022-configurable-worktree-dir.md) introduces aworktree:section so operators can choose where worktrees land and enable worktree mode for normal clones. This step covers config-file parsing only: no filesystem checks yet, no worktree-creation changes.The config loader lives in
src/config/services/configFile.ts:parseConfigFileYaml(contents, filePath)is a pure function that strictly validates the YAML and throwsConfigFileErroron unknown keys or wrong types. Private helpers:requireRecord,assertOnlyKeys,requireBoolean,requireString,requireEnum,requirePositiveInt,requireStringArray.docs:section parses intoDocsFileConfigwithDOCS_KEYS = ['enabled', 'paths', 'exclude'], using those same helpers.ConfigFileResultis also returned byemptyConfigFileResult()when the file is absent.loadConfigFile(cwd)readscwd/piloop-config.yamland callsparseConfigFileYaml; errors flow toreportConfigFileErrorinsrc/cli/services/runCli.ts→error.jsonwithkind: config, a stderr message, exit 1.src/config/index.tsre-exports the config surface (types likeDocsFileConfig).Decision table this step enforces at the parser level (ADR-022 §2):
enableddirworktree: {}), no errortruedirvalue validated by a later steptrueConfigFileError— no silent fallbackfalsedirnever validatedDepends on: none — this is the first step of the series.
Implementation Details
Files:
src/config/services/configFile.ts,src/config/index.ts; tests insrc/config/services/configFile.test.ts.Add the exported interface (mirrors
DocsFileConfig):Add
worktree: WorktreeFileConfigtoConfigFileResult, andworktree: {}toemptyConfigFileResult().Add
'worktree'toTOP_LEVEL_KEYS; addconst WORKTREE_KEYS = ['enabled', 'dir'] as const(same style asDOCS_KEYS).Parse the section alongside the existing
docsblock:requireRecord(raw.worktree, 'worktree', filePath)→assertOnlyKeys(section, WORKTREE_KEYS, 'worktree', filePath)→requireBoolean(section.enabled, 'worktree.enabled', filePath)when present →requireString(section.dir, 'worktree.dir', filePath)when present.Cross-field rule (no hidden defaults):
Do not validate the value of
dirwhenenabledis false — a disabled setting must never fail a run.Export the
WorktreeFileConfigtype fromsrc/config/index.tsalongsideDocsFileConfig.Acceptance Criteria
worktree: { dir: /x }(noenabled) parses and yieldsworktree.dir === '/x'.worktree: { enabled: true }withoutdirthrowsConfigFileErrornamingworktree.dir.worktree: { enabled: false }withoutdirparses without error.worktree: { enabled: false, dir: 'relative/path' }parses without error (parser performs nodirchecks).worktree: { dir: /x, mode: y }(unknown key) throwsConfigFileErrornamingworktree.mode.worktree: true(not a mapping) throwsConfigFileErrorfromrequireRecord.worktree: { enabled: "yes" }throwsConfigFileErrorfromrequireBoolean.npm run lintandnpm testpass; no existing tests modified.Test Plan
Add unit tests in
src/config/services/configFile.test.tscovering the seven parse cases above (the file already contains preset-config tests and an example-YAMLdescribeblock — follow the existing style). Runnpm testand confirm the new tests pass and the existing config tests are untouched.pi-loop opened and merged a pull request for this issue: #326