F3 SLICE-3: pending-edit registry + sidecar section-merge update (INV-9 groundwork) (#6)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+22
-1
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { serializeArtifact, type Artifact } from "./model";
|
||||
import { emptyArtifact, serializeArtifact, type Artifact } from "./model";
|
||||
|
||||
export class CoauthorStore {
|
||||
/** @param rootDir absolute workspace-folder root that owns the `.threads/` tree. */
|
||||
@@ -28,4 +28,25 @@ export class CoauthorStore {
|
||||
fs.mkdirSync(path.dirname(p), { recursive: true });
|
||||
fs.writeFileSync(p, serializeArtifact(artifact), "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-modify-write for sidecar co-ownership (spec F3 §6.2): each controller
|
||||
* mutates only its own section against a FRESH load, so ThreadController and
|
||||
* AttributionController never clobber each other. After the mutation, anchors
|
||||
* referenced by neither threads nor attributions are pruned (proposals are
|
||||
* still empty in F3 — revisit in F4).
|
||||
*/
|
||||
update(docPath: string, mutate: (artifact: Artifact) => void): Artifact {
|
||||
const artifact = this.load(docPath) ?? emptyArtifact(docPath);
|
||||
mutate(artifact);
|
||||
const referenced = new Set<string>([
|
||||
...artifact.threads.map((t) => t.anchorId),
|
||||
...artifact.attributions.map((a) => a.anchorId),
|
||||
]);
|
||||
for (const id of Object.keys(artifact.anchors)) {
|
||||
if (!referenced.has(id)) delete artifact.anchors[id];
|
||||
}
|
||||
this.save(docPath, artifact);
|
||||
return artifact;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user