Repository navigation
LOOP Continuity: durable run state (ADR 0002, all phases P0-P4) - #1
Open
killerdasher wants to merge 12 commits into
Open
killerdasher wants to merge 12 commits into
killerdasher wants to merge 12 commits into
Conversation
…endum ADR 0002: durable run state (.loop/continuity.json), four lifecycle commands, resume gates, and the amended constraints from the 2026-11-05 owner architecture review: - optional zero-dep helper scripts/continuity.mjs; BLOCKED degradation; skill-first workflow unchanged without it (ADR 0001 addendum) - run status ACTIVE|PAUSED|RECOVERY_REQUIRED|BLOCKED|COMPLETED|CANCELLED with separate integrity VALID|SUSPECTED_STALE|CORRUPT - no automatic resume; read-only reconciliation first; interrupted stage -> RECOVERY_REQUIRED; no bounded-loss promise - concurrency is an operational rule; generation detects stale snapshots, not locking; no --force in the first release - privacy: .loop/ git-excluded by instruction, no tokens/env values, best-effort secret scan, sanitized remote-URL fingerprints - atomic writes (tmp+rename) and retained .loop/archive/ terminal runs - verbatim capability-boundary table for docs Gates: validate --all 123/123, selftest 79/79, git diff --check clean.
…erage scripts/continuity.mjs (optional, zero-external-dep Node >=16.7 helper): - schema v1: six run statuses + separate integrity dimension, allowlisted fields, stopReason retained as terminal evidence (ADR 0002 field list updated) - documented transition table; invalid/unknown/terminal transitions are hard errors (never silent no-ops) - sanitized remote-URL identity fingerprints (userinfo stripped before hashing; only scheme/host/path enters the hash) - atomic persistence: <target>.tmp-<generation> + fsync + rename; left-behind temps reported by inspect and reconciled by 'repair' only when provably superseded (unparseable temps are refused) - corrupt / unsupported-schema state: read-only, never overwritten; transitions and updates refuse with BLOCKED class (CLI exit 2) - cancel/complete archive to .loop/archive/<taskId>.json; live file only removed after successful archive; archives never auto-deleted - best-effort secret scan fail-closed on match, limits documented in the file header and enforced by a validator check - defect found by test & fixed: identity mismatch is now mandatory for every state-mutating op (expectedRoot defaults to projectRoot) Installers (ps1+sh): copy the helper to <config>/scripts/continuity.mjs (outside skill dir, preserving skill-dir identity checks) and remove it on uninstall. validate.mjs: required-file entry, helper-copy installer markers, and new content checks (zero-dep, no-network, status vocabulary, documented secret-scan limits). selftest.mjs: 32 new checks importing the REAL module + real CLI exit-code contract (0/1/2/3), fake secret shapes assembled at runtime so repo text never carries a matchable pattern. Gates: validate --all 128/128, selftest 111/111, git diff --check clean.
- four thin commands: /loop-status (read-only inspect + git reality cross-check), /loop-pause (ACTIVE-only, honest boundary language), /loop-resume (full gate order: integrity/identity/no-auto-resume/ read-only reconciliation/operator approval, then restore into the nine-stage loop at the recorded stage), /loop-cancel (cancel+archive, never deletes terminal evidence). All route through the continuity helper, report BLOCKED with exact reasons when it cannot run, and never offer --force (the one legitimate mention is the negative statement, which the new validator check strips before scanning). - SKILL.md: Stage 0 detects live checkpoints and refuses a silent second run (write-before-act when helper available, BLOCKED otherwise); Stage 8 records completion through the helper and archives; PAUSED-not-COMPLETED on early stops; reference pointer added to the reporting-contract list. - new reference: skills/loop-engine/references/continuity.md (mechanism honesty table verbatim from ADR 0002 SS7, helper search paths with degradation contract, state vocabulary, write protocol, resume gates). - validate.mjs: required-file + reference-list entries; per-command structural checks (frontmatter, description, \, continuation reference route, BLOCKED language, no-force) and installer matrix hardening: fresh-global-install now verifies helper byte-identity, uninstall-removes-with-backup verifies helper removal. Gates: validate --all 162/162 (119+27+16), selftest 111/111.
- 9 new defect-injection mutations, each pinned to a check that was only a print in P2: continuity-command argument placeholder, BLOCKED path, --force offering (strips the negation sentence properly), helper non-builtin import, helper network primitive, status vocabulary, secret-scan limitation language, installer helper-copy lines (all helper plumbing, not just the copy step - a partial removal slipped past the mention-marker and that hole is documented in the mutation), and continuity reference deletion. Mutation count 27 -> 36. - two new real-module integrity checks: SUSPECTED_STALE persists through opUpdate; undocumented integrity values are rejected by the schema. Gates: validate --all 171/171 (119+36+16), selftest 113/113.
- docs/continuity.md: user-facing guide carrying the ADR 0002 SS7 capability table verbatim, command table, gate sequence, atomic-write and privacy chapters, and the four honest limitation anchors (no guaranteed checkpoints, no bounded-loss promise, no locking, no --force) enforced by the validator. - README: continuity command block, limitations entry, repository-tree and docs-table rows, check-count counter now reads 280+ (171 validator + 113 selftest actual). - docs/architecture.md: three-tier continuity section. - CHANGELOG: [Unreleased] documents the whole Continuity feature set, the identity-enforcement fix from P1, skill touchpoints, and the validation growth. - validator: docs:continuity-table (verbatim SS7 anchors), docs:continuity-limits, docs:readme-continuity + 3 new mutations (helper tier drift, promise inflation, README command removal). Gates: validate --all 178/178 (123+39+16), selftest 113/113, git diff --check clean.
P0 finalization pass (ADR-file-only scope, no functionality changes): - section 2 contradiction resolved: corrupt state is preserved in place byte-for-byte; the earlier 'renamed *.corrupt-<ts>' example becomes an explicit-operator-only action - full implemented transition table added (14 pairs incl. block/unblock/ recovery-flag from PAUSED; terminal-state transitions are errors) - exact schema v1 field table matching the helper validator (settings, stopReason, recovery shape, advisory createdBy) - command contracts (preconditions/mutations/refusals) for the four commands - acceptance criteria mapped to the implemented checker IDs - P1-P3 plan annotated with actual ship status on branch continuity (P1 90d7cec, P2 e691a06, P3 a6b7560, P4 905f5e7; PR #1, CI 42209037515 green, not released; main untouched until merge) - parked decisions recorded: --force/supersede, Case J, corrupt-file relocation helper, archive pruning - migration risks and maintenance costs documented Gates: validate --all 178/178, selftest 113/113, git diff --check clean.
Fresh P1 spec-vs-implementation review (9 items) found one real gap: taskId was format-checked on load but drifted/hand-edited IDs were accepted. Hardened into an enforced derivation invariant: - validateStateObject recomputes taskIdFor(objective, createdAt) and rejects mismatch as invalid -> inspectState classifies CORRUPT, all state-mutating ops refuse (transition blocked), corrupted bytes preserved in place (never silently reset) - opUpdate already validates the merged state pre-write, so objective patches that would break the derivation are refused before persist - tests: continuity:task-identity-invariant-holds (derivation round- trips) + continuity:task-identity-tamper-rejected (objective tampered ON DISK -> CORRUPT + blocked transition + bytes equal) No command or skill changes (out of P1 scope). Gates: validate --all 178/178, selftest 115/115 (113 + 2 new), git diff --check clean.
…pause Fresh P2 spec-vs-implementation review of the four lifecycle commands and skill integration (all items verified shipped: e691a06): - one LOW finding closed: loop-pause.md carried a stale 'RELAUNCH-IN-PROGRESS' template note naming a state that does not exist in the six-state vocabulary; reworded to 'Status gate:' - loop.md intentionally unchanged per ADR 0002 file structure (thin /loop router; continuity touchpoints live in SKILL.md Stage 0/8 + references/continuity.md; validator mutations pin this) Gates: validate --all 178/178, selftest 115/115, git diff --check clean.
New scripts/evaluator.mjs (zero-external-dep, Node >= 16.7): - evidence manifest .loop/verification.json (schema v1, atomic writes via the continuity helper's writeJsonAtomic; appends via 'record --from-stdin') - criteria MUST/SHOULD/COULD with optional deliverable artifacts; evidence verdicts; exec entries = deterministic (argv, no shell) + advisory entries cap at NEEDS_REVIEW; findings with severities; blockers - outcomes PASS | FAIL | BLOCKED | NEEDS_REVIEW (exit 0/1/2/3), fail-closed precedence: FAIL decisive; missing/invalid/corrupt/secret-flagged manifest, zero criteria, unresolved blockers, open CRITICAL/HIGH, uncovered MUST -> BLOCKED; advisory-only MUST / uncovered SHOULD -> NEEDS_REVIEW - --fresh re-executes every deterministic PASS command and lets the real exit code override recorded claims (tampered verdicts exposed) - binds to the live continuity task's taskId; refuses cross-run and identity-mismatched planted manifests (fail-closed) - no external evaluator model, no paid API, nothing remote Integration (nine-stage methodology unchanged): - SKILL.md Stage 8 completion-verdict touchpoint; references/continuity.md completion-evidence protocol; docs/evaluator.md guide; CHANGELOG entry - validator: 8 new evaluator:checks (implementation, vocabulary, exit contract, skill touchpoint, reference section, docs guide, changelog, nine-stages-intact) Tests: selftest 131/131 (16 new evaluator checks: positive pass/binding/ fresh-rerun/recovery, negative fail/missing/advisory/blockers/recover, adversarial tamper-exposure/cross-task/foreign-identity/no-criteria/ corrupt-preserved, CLI secret-refused/help-contract). validate --all 187/187.
New scripts/profiles.mjs (zero-external-dep) + five modular references under references/profiles/ (build, debug, refactor, audit, migrate): - every profile defines the same seven dimensions: required inputs, relevant analysis stages, verification methods, risk priorities, completion criteria, forbidden shortcuts, expected evidence - selection is explicit user intent only: --profile <name> on /loop, resolved deterministically (case/space tolerant); unknown names refused with the valid list - never silently defaulted - and the run continues as the generic nine-stage loop with the correction stated - task scope never overridden: only the --profile flag is stripped, every other byte of the task text (incl. other flags, line breaks, whitespace runs) is preserved verbatim; last flag wins with a correction note; a valueless --profile is refused - universal safeguards bound in every reference (anchor validated) and by the SKILL.md dispatch: nine stages + hard safety rules unchanged; profiles only add specificity, never remove a stage or loosen the Stage 8 evidence requirements - AUDIT is read-only by design: fixes are a separate, explicitly authorized re-scope, never a silent side effect - resolver: resolve/strip/task CLI, exit 0/4; findings fixed in-run: resolveFromTask field mismatch (would have silently gone generic - the failure class the resolver exists to prevent), verbatim whitespace semantics now asserted by the tests Integration: loop.md flag docs, SKILL.md Stage 0 dispatch note, docs/profiles.md, CHANGELOG; validator +10 profiles:checks (5 refs pinned for all seven dimensions + anchor, resolver, loop flag, skill dispatch, docs guide, changelog). Tests: selftest 143/143 (12 new checks incl. adversarial unknown-name, missing-value, last-wins, CLI contract, verbatim scope). validate --all 203/203.
Evidence-backed evaluation of LOOP-compatible models on identical tasks in controlled environments. scripts/model-eval.mjs (zero-dep) measures the eight P6 dimensions from completed evaluation records; the task set is version-pinned (v1.0.0) and hash-pinned into every record, so comparisons across differing task sets are refused. No ranking is derivable by construction: comparisons emit per-dimension observed counts with an explicit non-ranking disclaimer; profiles emit counts plus a sample-size classification (INSUFFICIENT_SAMPLE below 3 tasks per dimension, never scored), and completion requires an explicit limitations statement. Fail-closed records: unknown-field refusal, secret-shape scanning on every write, atomic writes, deterministic runIds with duplicate refusal, completed records immutable. Runs are operator-gated: no credentials handled or stored, no provider called or switched. Core tests validate the framework offline on fixture records (no paid API). Token-gated limit disclosed: zero real model profiles ship - producing one requires an operator-initiated run. Gates: validate --all 213/213 (158 structural + 39 mutations + 16 installer), selftest 156/156 (13 new model-eval checks + 1 immutability check), git diff --check clean.
Ten-step, evidence-driven improvement system for LOOP's own artifacts: scripts/evolution.mjs collects sanitized evaluation outcomes (validated continuity archives + evaluator manifests) into an append-only ledger (history never rewritten; integrity-suspect sources refused), classifies weaknesses into instructions/references/validation/recovery with a versioned keyword classifier and a recurring threshold, and refuses proposals that do not map to recorded failed evaluation cases. Candidates are verified in detached git worktrees under the OS temp dir (the active skill and repository are never touched; .opencode data dirs are refused outright); the full regression suite runs on both sides with no shell, and comparison is deterministic per Summary tier: any regression hard-rejects the candidate (REJECTED is final and unapprovable, evidence preserved). Adoption requires a measurable improvement (strictly more passing checks, zero regressions) plus an explicit --approved-by, recorded as a decision only - appliedByTool is always false, nothing is published automatically. Model claims are carried but labeled evidence:false and never influence verdicts. Records are schema-pinned v1, content-hash ids, secret-scanned, atomically written. Honest scope: LOOP does not learn model weights and holds no permanent autonomous intelligence - evolution means human-approved, regression-gated artifact changes. Gates: validate --all 225/225 (170 structural + 39 mutations + 16 installer), selftest 168/168 (12 new evolution checks incl. real worktree E2E, regression rejection, approval gate, traversal refusal), git diff --check clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LOOP Continuity - durable run state across sessions (ADR 0002)
Implements the owner-approved architecture review (2026-11-05, "APPROVED WITH AMENDMENTS") across all phases:
docs/adr/0002-loop-continuity.mddecision record with all seven amendments folded in; ADR 0001 addendum distinguishing skill-first architecture from helper-backed persistence.scripts/continuity.mjs: optional, zero-external-dependency helper (Node >= 16.7). Schema v1 (six run statuses + separate integrity dimension), documented transition table with invalid transitions as hard errors, sanitized remote-URL identity fingerprints, atomic persistence (temp + fsync + rename, recoverable temps, repair only removes provably superseded leftovers), corrupt/unsupported state never silently overwritten, cancel/complete archiving with retained terminal evidence, best-effort secret scanner with documented limits. Identity-enforcement gap found by the real-module tests before any command shipped and fixed./loop-status,/loop-pause,/loop-resume,/loop-cancel) with the full resume-gate sequence (integrity, identity, no automatic resume, read-only reconciliation, explicit operator approval, restore at the recorded stage); no--forceanywhere. SKILL.md Stage 0 checkpoint detection + Stage 8 archive rule. New referencereferences/continuity.md. Installer helper copy outside the skill dir (slice-identity checks stay exact) + uninstall.docs/continuity.mdwith the ADR 0002 section 7 capability table verbatim; README command block, limitations, structure/docs rows; architecture section; CHANGELOG[Unreleased]; validator docs anchors + 3 more mutations.Acceptance verification (owner checklist, real implementation only)
continuity:corrupt-*(refuse-not-wipe, byte preservation, transition BLOCKED, restoral after repair).continuity:unsupported-schema-*.continuity:invalid-transitions-error.continuity:secret-shaped-values-refused,continuity:update-refuses-secret-patch, validatorcontinuity:limits-documented+ mutation.continuity:identity-mismatch-refused(this check proved the P1 gap).continuity:stale-integrity-persisted,continuity:undocumented-integrity-rejected.continuity:cancel-archives,continuity:archive-retained-terminal-evidence.continuity:atomic-write-no-temp-on-success,continuity:interrupted-temps-reported,continuity:repair-removes-superseded-temps-only.Gates
node scripts/validate.mjs --all178/178 (123 structural + 39 mutations + 16 installer scenarios) andnode tests/harness/selftest.mjs113/113,git diff --checkclean.No release is published here; merge gates CI, not a version bump.