feat(ms-ai-architect): Sesjon 18 — B3 apply-path (sanitize+retire), merge→S19 [skip-docs]
Apply-path = den destruktive frontieren: eksekver en operatør-godkjent
(status:approved) ledger-entry → faktisk skills/-mutasjon. Staget per
operatør-beslutning til single-skill ops (sanitize+retire); merge-apply
isoleres til S19 (krever taksonomi-persistering + cross-skill flytt).
- revalidateApply (ren, skill-ops.mjs): idempotent revalidering mot fersk
re-plan — nekter ved status≠approved, op-mismatch, fersk guardrail≠ok,
eller drift (isDeepStrictEqual fresh vs approved guardrail-snapshot).
- applyApprovedAction (impur): arkiver-så-slett (rename skills/…→archive/…
atomisk; retire rmdir'er tom katalog sist) + flipp ledger approved→applied.
apply:false = preview (0 mutasjon). merge_skills → throw (S19).
- setActionStatus (ren, decisions-io.mjs): ledger status-transisjon, bevarer
targets+guardrail, audit-record beholdes.
- CLI apply-skill-op.mjs {list|sanitize|retire} — default PREVIEW, --apply =
dobbel-gate utover ledger-approved.
TDD, tmpdir-fixtures: 0 ekte skills/-mutasjon. Tester: kb-eval 66→78,
kb-update 132→137; validate 239 · kb-integrity 192/192 uendret.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f7b622b318
commit
4ac18a76c8
5 changed files with 603 additions and 2 deletions
|
|
@ -158,3 +158,29 @@ export function listActions(ledger, status = null) {
|
|||
const all = Object.values(ledger.actions ?? {});
|
||||
return status ? all.filter((a) => a.status === status) : all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition a recorded action to a new status. Pure — returns a new ledger,
|
||||
* does not mutate. Every other field (targets, guardrail, note) is preserved.
|
||||
* This is the apply-path's one write primitive (Sesjon 18): after a successful
|
||||
* skills/ mutation it flips the operator-approved entry approved -> applied,
|
||||
* keeping the entry as an audit record (policy A dedup still holds).
|
||||
* @param {object} ledger
|
||||
* @param {string} key — from actionKey()
|
||||
* @param {string} status — new status (e.g. 'approved', 'applied')
|
||||
* @param {string|null} [decided_at] — when given, advances the entry date + updated_at
|
||||
* @returns {object} new ledger
|
||||
* @throws if no action exists under `key`
|
||||
*/
|
||||
export function setActionStatus(ledger, key, status, decided_at = null) {
|
||||
const existing = ledger.actions?.[key];
|
||||
if (!existing) throw new Error(`setActionStatus: no action recorded under key "${key}"`);
|
||||
return {
|
||||
...ledger,
|
||||
updated_at: decided_at ?? ledger.updated_at,
|
||||
actions: {
|
||||
...ledger.actions,
|
||||
[key]: { ...existing, status, decided_at: decided_at ?? existing.decided_at },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue