Abstract Class: ChangeRepository
Defined in: packages/core/src/application/ports/change-repository.ts:24
Port for reading and writing changes.
Extends Repository for interface consistency with SpecRepository
and ArchiveRepository, but changes are stored globally (one changes/
directory), not per-workspace. The inherited workspace(), ownership(), and
isExternal() fields carry the default workspace values and are not used by
any use case. They exist solely to satisfy the shared Repository base
contract.
list and get return Change objects with artifact state
(status, validatedHash) but without artifact content. Content is loaded
on demand via artifact(). The manifest (state, hashes, approvals) is
persisted separately from artifact file content via save() and
saveArtifact().
Extends
Constructors
Constructor
new ChangeRepository(
config):ChangeRepository
Defined in: packages/core/src/application/ports/change-repository.ts:30
Creates a new ChangeRepository instance.
Parameters
config
Workspace, ownership, and locality configuration
Returns
ChangeRepository
Overrides
Methods
artifact()
abstractartifact(change,filename):Promise<SpecArtifact|null>
Defined in: packages/core/src/application/ports/change-repository.ts:128
Loads the content of a single artifact file within a change.
The returned SpecArtifact has originalHash set to the sha256 of
the content read from disk, enabling conflict detection if the artifact
is later saved back via saveArtifact().
Parameters
change
The change containing the artifact
filename
string
The artifact filename to load (e.g. "proposal.md")
Returns
Promise<SpecArtifact | null>
The artifact with content and originalHash, or null if the file does not exist
artifactExists()
abstractartifactExists(change,filename):Promise<boolean>
Defined in: packages/core/src/application/ports/change-repository.ts:171
Parameters
change
filename
string
Returns
Promise<boolean>
changePath()
abstractchangePath(change):string
Defined in: packages/core/src/application/ports/change-repository.ts:169
Returns the absolute filesystem path to the active change directory.
Used by use cases to build the change.path template variable.
Parameters
change
The change whose path is needed
Returns
string
Absolute path to the change directory
delete()
abstractdelete(change):Promise<void>
Defined in: packages/core/src/application/ports/change-repository.ts:115
Deletes the entire change directory and all its contents.
Parameters
change
The change to delete
Returns
Promise<void>
deltaExists()
abstractdeltaExists(change,specId,filename):Promise<boolean>
Defined in: packages/core/src/application/ports/change-repository.ts:181
Checks whether a delta file exists for a change + specId pair.
Parameters
change
The change containing the delta
specId
string
The spec identifier (e.g. "auth/login")
filename
string
The delta filename to check (e.g. "spec.delta.yaml")
Returns
Promise<boolean>
true if the file exists, false otherwise
get()
abstractget(name):Promise<Change|null>
Defined in: packages/core/src/application/ports/change-repository.ts:49
Returns the change with the given name, or null if not found.
Loads the manifest and derives each artifact's status by comparing
the current file hash against the validatedHash stored at last
validation. A hash mismatch indicates drift and resets the artifact
status to in-progress.
This is a snapshot read only. Callers that need a concurrency-safe
read-modify-write section for an existing persisted change must use
mutate instead of pairing get() with a later save().
Parameters
name
string
The change name (e.g. "add-oauth-login")
Returns
Promise<Change | null>
The change with current artifact state, or null if not found
isExternal()
isExternal():
boolean
Defined in: packages/core/src/application/ports/repository.ts:71
Returns whether this repository points to data outside the current git repository.
Returns
boolean
true if this repository is external to the current git root
Inherited from
list()
abstractlist():Promise<Change[]>
Defined in: packages/core/src/application/ports/change-repository.ts:76
Lists all active (non-drafted, non-discarded) changes, sorted by creation order.
Returns Change objects with artifact state but without content.
Returns
Promise<Change[]>
All active changes in this workspace, oldest first
listDiscarded()
abstractlistDiscarded():Promise<Change[]>
Defined in: packages/core/src/application/ports/change-repository.ts:94
Lists all discarded changes in this workspace, sorted by creation order.
Returns Change objects with artifact state but without content.
Returns
Promise<Change[]>
All discarded changes in this workspace, oldest first
listDrafts()
abstractlistDrafts():Promise<Change[]>
Defined in: packages/core/src/application/ports/change-repository.ts:85
Lists all drafted (shelved) changes in this workspace, sorted by creation order.
Returns Change objects with artifact state but without content.
Returns
Promise<Change[]>
All drafted changes in this workspace, oldest first
mutate()
abstractmutate<T>(name,fn):Promise<T>
Defined in: packages/core/src/application/ports/change-repository.ts:67
Runs a serialized persisted mutation for one existing change.
The repository acquires exclusive mutation access for name, reloads the
freshest persisted Change, invokes fn(change), persists the updated
manifest if fn succeeds, and then releases the exclusive access.
This is the only concurrency-safe read-modify-write API for an existing change. Exclusive access is scoped per change name; unrelated change names may mutate concurrently.
Type Parameters
T
T
Parameters
name
string
The change name to mutate
fn
(change) => T | Promise<T>
Callback that applies the mutation on the fresh persisted change
Returns
Promise<T>
The callback result after the manifest has been persisted
Throws
If no change with the given name exists
ownership()
ownership():
"owned"|"shared"|"readOnly"
Defined in: packages/core/src/application/ports/repository.ts:62
Returns the ownership level of this repository, as declared in specd.yaml.
Returns
"owned" | "shared" | "readOnly"
The ownership level
Inherited from
save()
abstractsave(change):Promise<void>
Defined in: packages/core/src/application/ports/change-repository.ts:108
Persists the change manifest — state, artifact statuses, validated hashes, and approvals.
Does not write artifact file content. Use saveArtifact() for that.
This is a low-level manifest persistence primitive. Atomic writing prevents
partial-file corruption, but save() alone does not serialize a caller's
earlier snapshot read.
Parameters
change
The change whose manifest should be persisted
Returns
Promise<void>
saveArtifact()
abstractsaveArtifact(change,artifact,options?):Promise<void>
Defined in: packages/core/src/application/ports/change-repository.ts:148
Writes an artifact file within a change directory.
If artifact.originalHash is set and does not match the current file on
disk, the save is rejected with ArtifactConflictError to prevent
silently overwriting concurrent changes (e.g. those made by an LLM agent).
Pass { force: true } to overwrite regardless.
After a successful write the corresponding ChangeArtifact status in the
change manifest is reset to in-progress — call save(change) to persist
that state change.
Parameters
change
The change to write the artifact into
artifact
The artifact to save (filename + content)
options?
Save options
force?
boolean
When true, skip conflict detection and overwrite unconditionally
Returns
Promise<void>
Throws
When a concurrent modification is detected and force is not set
scaffold()
abstractscaffold(change,specExists):Promise<void>
Defined in: packages/core/src/application/ports/change-repository.ts:193
Ensures artifact directories exist for all files tracked by the change.
For scope: spec artifacts, creates specs/<ws>/<capPath>/ or
deltas/<ws>/<capPath>/ directories under the change directory.
For scope: change artifacts, the root directory already exists.
Parameters
change
The change whose artifact directories to scaffold
specExists
(specId) => Promise<boolean>
A function that returns whether a spec already exists in the repository
Returns
Promise<void>
unscaffold()
abstractunscaffold(change,specIds):Promise<void>
Defined in: packages/core/src/application/ports/change-repository.ts:205
Removes the scaffolded directories for the given spec IDs from the change directory.
For each spec ID, removes both specs/<workspace>/<capability-path>/ and
deltas/<workspace>/<capability-path>/ directories. The operation is idempotent —
if a directory does not exist, it is silently skipped.
Parameters
change
The change whose spec directories to remove
specIds
readonly string[]
The spec IDs whose directories to remove
Returns
Promise<void>
workspace()
workspace():
string
Defined in: packages/core/src/application/ports/repository.ts:53
Returns the workspace name this repository is bound to.
Returns
string
The workspace name (e.g. "billing", "default")