From b316a5b683d42c10173ba826814eb472b641e2be Mon Sep 17 00:00:00 2001 From: specter119 Date: Sat, 19 Sep 2026 11:53:34 +0800 Subject: [PATCH] docs(repo): align documentation scopes and skill tooling --- .agents/skills/luwu-boundary-review/SKILL.md | 29 ++ .../luwu-confidentiality-review/SKILL.md | 28 ++ .agents/skills/luwu-consent-review/SKILL.md | 27 ++ .agents/skills/luwu-ownership-review/SKILL.md | 29 ++ .../luwu-semantic-drift-review/SKILL.md | 34 +- .../skills/luwu-verifiability-review/SKILL.md | 29 ++ AGENTS.md | 183 ++++++---- README.md | 43 ++- docs/design.md | 268 +++++--------- docs/maintenance.md | 68 +++- docs/milestones/m1.md | 4 + docs/milestones/m2.md | 4 + docs/milestones/m3-execution-closure.md | 233 ++++-------- docs/milestones/m3-followup.md | 172 ++++----- docs/milestones/m3-repair-plan.md | 168 ++++----- docs/milestones/m3.md | 189 ++++------ docs/milestones/m4.md | 344 +++++------------- docs/product.md | 9 +- docs/roadmap.md | 43 ++- docs/status.md | 317 +++------------- prek.toml | 19 +- 21 files changed, 944 insertions(+), 1296 deletions(-) diff --git a/.agents/skills/luwu-boundary-review/SKILL.md b/.agents/skills/luwu-boundary-review/SKILL.md index 641a6de..a1aa86c 100644 --- a/.agents/skills/luwu-boundary-review/SKILL.md +++ b/.agents/skills/luwu-boundary-review/SKILL.md @@ -44,3 +44,32 @@ concrete path/line and test evidence, failure impact, and minimum fix. Classify implemented, partial, design-only, or unstarted behavior and require a focused regression test for every changed shield. Use `docs/reference.md` for the stable write contract and `docs/design.md` for its mechanism. + +## Scope boundary + +This stance owns filesystem and resource-boundary questions: path roots, +symlinks, descriptors, permissions, replacement, cleanup, and recoverability. +It does not own who is authorized to change a value, whether an action had +consent, what a representation means, or whether a claim is current. Hand +those findings to the ownership, consent, semantic-drift, or verifiability +stance instead of redefining their contracts here. + +## Good patterns + +- Re-observe staged no-follow identity at a replace boundary and classify an + uncertain result as unknown instead of inferring it from equal bytes. + Evidence: [M3 repair record](../../../docs/milestones/m3-repair-plan.md). +- Check journal and lock paths together before either persistent entry is + created. Evidence: [M3 follow-up record](../../../docs/milestones/m3-followup.md). + +## Bad patterns + +- Treat equal target content as proof that this process performed the + replacement. This loses provenance at the exact boundary where the writer + may have raised. +- Create a journal lock or temporary entry before checking its full path + relationship with declared resources. This can mutate a declared target + before the requested operation begins. + +Patterns are review evidence, not a replacement for the public write contract. +Promote a repeated pattern only in the owning document and link back here. diff --git a/.agents/skills/luwu-confidentiality-review/SKILL.md b/.agents/skills/luwu-confidentiality-review/SKILL.md index de49929..8591681 100644 --- a/.agents/skills/luwu-confidentiality-review/SKILL.md +++ b/.agents/skills/luwu-confidentiality-review/SKILL.md @@ -46,3 +46,31 @@ Report the value flow, exposure boundary, path/line and test evidence, rejected diagnostic convenience, minimum fix, and regression test. Classify implemented, partial, design-only, or unstarted. Use the owning reference and provider contract for exact secrecy promises. + +## Scope boundary + +This stance owns sensitive-value and capability exposure: secrets, rendered +content, metadata, logs, subprocesses, networks, caches, backups, and error +surfaces. It does not own filesystem replacement correctness, authorization +transitions, configuration authority, semantic equivalence, or documentation +status. Refer those questions to the boundary, consent, ownership, +semantic-drift, or verifiability stance. + +## Good patterns + +- Require explicit runtime authority, a bounded provider adapter, and fixed + safe error projections before a provider can run. Evidence: the M4 closure + record and the v6 contract in `docs/reference.md`. +- Keep journals and caches metadata-only, and use a fake provider or injected + resolver for tests rather than a real vault. Evidence: + [M4 closure record](../../../docs/milestones/m4.md). + +## Bad patterns + +- Persist provider references, rendered bytes, content hashes, or secret + derived metadata in a journal or cache merely to improve diagnostics. +- Run a real vault in a regression test or expose provider stdout/stderr in + an error, diff, log, or machine-readable result. + +Patterns are evidence for this review stance. The exact secrecy and capability +contract remains owned by `docs/reference.md`. diff --git a/.agents/skills/luwu-consent-review/SKILL.md b/.agents/skills/luwu-consent-review/SKILL.md index 70578e7..a7b1f7c 100644 --- a/.agents/skills/luwu-consent-review/SKILL.md +++ b/.agents/skills/luwu-consent-review/SKILL.md @@ -44,3 +44,30 @@ Report a short state-transition timeline with path/line and test evidence, classify behavior as implemented, partial, design-only, or unstarted, and name the smallest corrective change plus its regression test. Use the owning CLI or reference contract for exact exit codes and output promises. + +## Scope boundary + +This stance owns authorization transitions: observation, planning, +confirmation, stale revalidation, mutation, partial completion, and the next +safe action. It does not own path safety, secret exposure, configuration +authority, semantic equivalence, or document truth. Hand those findings to the +boundary, confidentiality, ownership, semantic-drift, or verifiability stance. + +## Good patterns + +- Keep inspect and plan read-only, require explicit confirmation for mutation, + and recalculate after the write. Evidence: the command contract in + `docs/reference.md`. +- Complete preflight before the first writer and keep recovery observation + read-only. Evidence: the M3 execution closure and v5 reference contract. + +## Bad patterns + +- Let inspection, planning, recovery, or cache status perform an implicit + write or refresh. +- Allow a selected reverse-sync field to proceed while another field in the + same resource requires conflict review. Evidence: + [M3 execution closure](../../../docs/milestones/m3-execution-closure.md). + +Patterns do not define confirmation flags or exit codes. Those remain owned by +the public CLI and reference contract. diff --git a/.agents/skills/luwu-ownership-review/SKILL.md b/.agents/skills/luwu-ownership-review/SKILL.md index 21b4223..b13c495 100644 --- a/.agents/skills/luwu-ownership-review/SKILL.md +++ b/.agents/skills/luwu-ownership-review/SKILL.md @@ -45,3 +45,32 @@ the protected authority, the convenience being sacrificed, path/line evidence, the failure scenario, the smallest corrective change, and the regression test. Use `docs/product.md` for the responsibility questions and the owning contract for the exact transition rules. + +## Scope boundary + +This stance owns responsibility and authority: declared owner, scope, +provenance, adoption, baseline role, provider/live role, and reverse-sync +eligibility. It does not own the filesystem mechanics, authorization prompt, +secret exposure, semantic equivalence, or current-document status. Route those +findings to the boundary, consent, confidentiality, semantic-drift, or +verifiability stance. + +## Good patterns + +- Treat an absent baseline as `unbased` and a change outside declared fields + as a separate undeclared signal; neither silently grants a candidate. + Evidence: the M3 contract in `docs/reference.md`. +- Permit reverse sync only through an explicit declared literal mapping and + preserve unselected or undeclared source content. Evidence: + [M3 repair record](../../../docs/milestones/m3-repair-plan.md). + +## Bad patterns + +- Use a generic force or precedence rule to adopt undeclared live content or + to erase a conflict. +- Re-read a convenient baseline and use it as authorization when the planner + classified a different baseline. Evidence: + [M3 follow-up record](../../../docs/milestones/m3-followup.md). + +Patterns explain how to attack authority mistakes; the resource and field +contract remains owned by `docs/product.md` and `docs/reference.md`. diff --git a/.agents/skills/luwu-semantic-drift-review/SKILL.md b/.agents/skills/luwu-semantic-drift-review/SKILL.md index 2250274..88bf177 100644 --- a/.agents/skills/luwu-semantic-drift-review/SKILL.md +++ b/.agents/skills/luwu-semantic-drift-review/SKILL.md @@ -3,8 +3,8 @@ name: luwu-semantic-drift-review description: >- Use when reviewing Luwu drift detection, rendering, normalization, formatting, parsers, structured comparison, or reverse synchronization. Test - whether the implementation distinguishes meaningful configuration changes from - presentation noise without changing ownership. Do not use for generic + whether the implementation distinguishes meaningful configuration changes + from presentation noise without changing ownership. Do not use for generic formatter or parser implementation review without a drift question. --- @@ -45,3 +45,33 @@ Report the equivalence contract, the authority it preserves, path/line and test evidence, the convenience traded away, and the minimum corrective change. Mark implemented, partial, design-only, or unstarted. Use `docs/product.md` for the semantic intent and `docs/reference.md` for current comparison states. + +## Scope boundary + +This stance owns meaning versus representation: equivalence relations, +normalization, parser subsets, formatting noise, information loss, and +semantic reverse-sync edits. It does not own who is authorized to change a +field, whether a mutation was confirmed, filesystem safety, sensitive-value +exposure, or documentation freshness. Route those findings to the ownership, +consent, boundary, confidentiality, or verifiability stance. + +## Good patterns + +- Define a narrow strict-JSON equivalence relation that preserves object + members and array order, distinguishes booleans from numbers, and reports + unsupported syntax as blocked. Evidence: the M2 contract in + `docs/reference.md`. +- Patch only selected literal-JSON spans so unselected and undeclared bytes are + preserved. Evidence: + [M3 repair record](../../../docs/milestones/m3-repair-plan.md). + +## Bad patterns + +- Re-encode a complete source object to update one selected field. This can + silently change whitespace, escaping, number spelling, or undeclared + content. +- Treat a generic formatter or parser as permission to discard unsupported + syntax or to call a semantically different document in sync. + +Patterns describe comparison risks. Parser names, supported syntax, and public +status values remain owned by the reference contract. diff --git a/.agents/skills/luwu-verifiability-review/SKILL.md b/.agents/skills/luwu-verifiability-review/SKILL.md index b035d3a..873eb37 100644 --- a/.agents/skills/luwu-verifiability-review/SKILL.md +++ b/.agents/skills/luwu-verifiability-review/SKILL.md @@ -47,3 +47,32 @@ Return a maturity matrix of implemented, partial, design-only, and unstarted claims, with path/line evidence, missing contract or test, and the smallest next practice. Use `docs/status.md` for current facts, `docs/reference.md` for stable contracts, and `docs/product.md` for future intent. + +## Scope boundary + +This stance owns evidence continuity: whether a claim is current, planned, +historical, testable, recoverable, and routed to one documentation owner. It +does not own the product value itself, public field semantics, implementation +mechanics, filesystem safety, secret exposure, consent, or configuration +authority. Route those findings to the product, reference, design, boundary, +confidentiality, consent, or ownership owner rather than restating them. + +## Good patterns + +- Keep current status as a small snapshot and retain dated test counts, + temporary paths, and closure reasoning in milestone records. Evidence: + [M4 closure record](../../../docs/milestones/m4.md) and + [current status](../../../docs/status.md). +- Separate target replacement facts from journal publication facts and expose + enough metadata for the next action without persisting content. Evidence: + [M3 execution closure](../../../docs/milestones/m3-execution-closure.md). + +## Bad patterns + +- Copy a closed milestone's test log and temporary artifact paths into the + current status page, creating two competing histories. +- Let a milestone, skill, or summary page redefine a stable field, state, or + error instead of linking to `docs/reference.md`. + +Patterns are evidence about maintainability. The status snapshot, public +contract, and historical records keep their own document owners. diff --git a/AGENTS.md b/AGENTS.md index 415e3ef..fa82b58 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,78 +1,123 @@ # Luwu Agent Instructions -## Document role +## Role and authority + +Luwu is still at the seed stage. This file is the entry point for agents and +maintainers. It owns agent working method, cross-cutting handling boundaries, +and documentation routing. It is not the product brief, public contract, +implementation design, status report, release handbook, or milestone history. + +The product seed is in [docs/product.md](docs/product.md). Planned behavior +must never be presented as current behavior. When a statement could describe +both a desired direction and an implementation fact, classify it before +editing a document. + +## Cross-cutting handling boundaries + +These are rules for agent and maintainer work. Their product rationale belongs +to `docs/product.md`; their public behavior belongs to `docs/reference.md`. + +- Keep observation and mutation separate. Inspection, planning, and ordinary + reverse sync must not write implicitly. A mutation is explicit and follows + an explainable plan. +- Keep scope and ownership explicit. Undeclared content is not implicitly + adoptable. Conflicts stop for review instead of being hidden by a generic + force or precedence rule. +- Treat reverse sync as structured, auditable acceptance. Only declared + fields may be written back, and the result is recalculated after the write. +- Minimize secrets and fail closed. Provider-managed secrets must not enter + repositories, persistent state, diffs, logs, caches, backups, or + machine-readable output. +- Preserve existing targets and recoverable boundaries. A successful + deployment is not worth damaging undeclared content, permissions, or + symlinks. +- Keep semantic responsibility ahead of implementation convenience. A + formatter, cache, or application side effect must not change who owns a + value. +- Make external capabilities explicit. Dependencies, subprocesses, and + network access must not bootstrap themselves at runtime. +- Label product goals, designs, implementation status, historical evidence, + and verification results honestly. + +## Documentation ownership + +Ownership is by **fact type**, not by which file first mentioned a subject. +Every normative fact has one owner. Other documents may summarize it with a +short sentence and a link, or record it as historical evidence, but must not +create a second definition. + +| Fact type | Sole owner | Allowed elsewhere | +| ------------------------------------------------------------------------------ | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | +| Product problem, direction, scope, non-goals, and value tests | `docs/product.md` | A short rationale or link; no CLI, schema, or current-status definition | +| Stable manifest, CLI, JSON, error, compatibility, and public safety contracts | `docs/reference.md` | Design explains mechanism; status says whether it is implemented; milestones record the historical decision or evidence | +| Current checkout implementation facts and latest verified state | `docs/status.md` | README gives a user summary; milestones preserve dated historical snapshots | +| Internal flow, module responsibilities, and implementation mechanisms | `docs/design.md` | Link to the public contract; do not redefine public fields or states | +| Delivery sequence and milestone boundaries | `docs/roadmap.md` | Milestones may expand their own historical scope; neither roadmap nor milestones redefine unrelated contracts | +| Development, test, release, migration, and documentation workflow | `docs/maintenance.md` | Commands may be shown as examples; their behavior is owned by `reference.md` | +| Fixed milestone scope, review decisions, counterexamples, and closure evidence | `docs/milestones/*.md` | Status links to the record; after closure, stable behavior is owned by `reference.md` | +| User overview and quick start | `README.md` | Link to the owner for details; do not copy internal history or contract tables | +| Review stance and attack playbook | `.agents/skills/*/SKILL.md` | Skills inspect the owner documents and implementation; they do not own product or API contracts | +| Why a high-impact cross-cutting choice was made | `docs/decisions/.md` when such a record exists | Link from the affected owner; do not create a decision record for routine implementation history | + +The map is a routing aid, not permission to duplicate content. A document may +mention the same subject at a different fact type: product says why, +reference says what, design says how, status says whether, a milestone says +what was true at a date, and a skill says how to attack the claim. The wording +must make that distinction visible. + +Do not use a non-owner document to repair a conflict. First identify the fact +type and owner, then update the owner and replace the other statement with a +link or a clearly dated historical note. Do not average conflicting +documents. For a closed milestone, do not rewrite history to match a later +implementation; record the later fact in the current owner. + +## Scope and language rules + +- Repository documentation is maintained in English. There is no + `README_cn.md` mirror. Do not add a second-language normative copy without a + separately approved owner and synchronization policy. +- A field list, state table, error meaning, or command promise belongs in + `docs/reference.md`, even when a milestone originally introduced it. +- A test count, temporary artifact path, or dated gate result belongs in the + relevant milestone record when it is historical. `docs/status.md` links to + it instead of replaying the log. +- A skill pattern is evidence for review, not a new product rule. Promote a + pattern to the relevant owner only when code, tests, or repeated maintenance + experience justify a stable rule. +- This file does not define subagent mutual exclusion or scheduling. Multiple + reviewers may inspect the same scope. Document ownership is a content + boundary, not a runtime lock. -Luwu is still at the seed stage. This file is the root entry point for agents and maintainers. It defines cross-cutting boundaries, documentation ownership, and a lightweight working method. - -It is not the complete product brief, architecture, API reference, testing handbook, release guide, or roadmap. Do not turn a currently attractive implementation idea into a permanent rule here. Route each concrete topic to its owning document. - -The product seed is in docs/product.md. Any document must distinguish its intended design from the current implementation; planned behavior must never be presented as existing behavior. - -## Product summary - -Luwu is a configuration orchestrator for dotfiles, developer tools, and agent configuration. It should make meaningful drift explainable, make responsibility visible, and let people choose an auditable next action. The product problem, scope, non-goals, and value tests belong to [docs/product.md](docs/product.md), not to this summary. - -## Non-negotiable boundaries +## Agent working method -- Observation and mutation are separate. Inspection, planning, and ordinary reverse sync must not write implicitly. A mutation must be explicit and preceded by an explainable plan. -- Scope and ownership are explicit. Undeclared content is not implicitly adoptable; conflicts stop for review instead of being hidden behind a generic force or precedence rule. -- Reverse sync is a structured, auditable acceptance process, not a file copy. Only declared fields may be written back, and the result must be recalculated after that write. -- Secrets are minimized and fail closed. Provider-managed secrets must not enter the repository, persistent state, diffs, logs, caches, backups, or machine-readable output. -- Writes must respect the existing target and retain a recoverable boundary. A successful deployment is not worth damaging undeclared content, permissions, or symlinks. -- Semantic responsibility comes before implementation convenience. A formatter, cache, or application side effect must not change who owns a value. -- External capabilities are explicit. Dependencies, subprocesses, and network access must not silently bootstrap themselves at runtime. -- Product goals, designs, implementation status, and verification results must be labeled honestly. +1. Read this file, then read the owner document for the requested change. +1. Inspect the actual code, schema, fixtures, tests, and current status needed + to distinguish implemented behavior from intent or history. +1. Classify each proposed statement as product intent, public contract, + current fact, design mechanism, workflow, historical evidence, or review + pattern. If two owners appear possible, stop and resolve the classification + before editing. +1. Change the owner. In other documents, replace repeated definitions with a + concise summary and a relative link. +1. Search the repository after editing for duplicate definitions, stale status + claims, broken owner links, and language-policy violations. +1. Run the narrowest relevant tests, documentation checks, and repository + gates. Mark blocked or unrun checks explicitly. +1. Report what changed, what remains outside scope, which evidence was used, + and how the next maintainer can continue. + +If `docs/status.md` does not exist, do not infer that planned capabilities are +implemented. Establish the status document when implementation starts. ## Shared vocabulary -These terms form a shared mental model; they do not prescribe a class hierarchy or storage format: - -- global and local: shared inputs and machine-private inputs; -- provider: a controlled external source of values, with its own provenance and sensitivity; -- live: configuration currently used or changed by an application or user; -- baseline: the last state explicitly accepted as a comparison point; -- desired: the state calculated from the current declared inputs; -- source, live, merge, provider, and ignore: ownership vocabulary for deciding how a field may change. - -Document ownership and configuration ownership are different. A document owner is an accountability pointer for maintaining and routing a document; it is not proof of authority or a source of truth. Configuration ownership must eventually affect allowed transitions and be enforced by the resource or field contract, planning, validation, and tests. - -Concrete reconciliation algorithms, field-path syntax, formatting rules, persistence layouts, and provider protocols belong in their owning documents. - -## Current starting point, not a permanent blueprint - -The seed implementation uses Python with uv, explicit `.j2` templates, and narrow provider boundaries; rbw is a first provider experiment. These are starting assumptions, not product invariants or a complete future architecture. Detailed contracts belong in the document that owns the subject and should be added when implementation and evidence make them useful. - -## Documentation map and single ownership - -Every normative fact has one owner. Other documents may summarize it briefly, but must link to the owner instead of copying a rule, field table, or competing explanation. - -| Document | Owns | Does not own | -| ------------------------------ | ----------------------------------------------------------------- | -------------------------------------------------------------------- | -| AGENTS.md | agent routing, global boundaries, and document governance | full product narrative, internal algorithms, command reference | -| README.md | user-facing overview, use cases, and quick start | agent workflow, internal contracts, decision history | -| docs/product.md | product problem, scope, non-goals, and value tests | implementation types, CLI fields, concrete algorithms | -| docs/roadmap.md | coarse delivery sequence and milestone boundaries | detailed contracts, current status, milestone closure records | -| docs/decisions/.md | why one high-impact choice was made and its consequences | the current contract or an interface inventory | -| docs/milestones/.md | fixed milestone scope, exit checklist, and closure record | current implementation status, product direction, detailed contracts | -| docs/design.md | how the current internal design works | product vision, user guide, complete public contract | -| docs/reference.md | stable manifest, CLI, JSON, error, and compatibility contracts | rationale, speculative designs, maintenance process | -| docs/maintenance.md | development, testing, release, migration, and dependency workflow | product goals or complete algorithm definitions | -| docs/status.md | what is implemented, exploratory, or not started | product scope or design authority | - -The map is a route, not a demand to create empty files. Create a specialist document only when a topic has an independent audience, change rate, or review boundary. A specialist document may include a short status or scope note when it prevents a real ambiguity; do not add `Owner`, `Scope`, or `Does not define` metadata as a ritual. If a status is used, it must distinguish early direction from accepted and verified behavior. - -README.md is for users, AGENTS.md is for agents, and decision records explain history rather than silently defining current behavior. If two documents disagree, do not average them: identify the owner, record the conflict, and repair the documentation. - -## Agent working method - -1. Read this file first, then read the owning document and the affected code, schema, fixtures, and tests required by the task. -1. Inspect the actual state before proposing a change. Treat planned behavior as unverified until code, tests, or a status document provide evidence. -1. Identify the owning layer and document. Update that owner when behavior changes; update this file only when a cross-cutting boundary or the documentation map changes. -1. Keep behavior, verification, schema or migration, and documentation aligned without duplicating normative rules. Create a decision record only for a high-impact choice. -1. Report actual changes and verification, including important checks not run and relevant security, migration, or documentation impact. Do not commit, push, or change branch policy unless asked. - -If docs/status.md does not exist, do not infer that planned capabilities are implemented; use evidence from code and tests, and establish that status document when implementation starts. +Use the product vocabulary consistently: global and local inputs, provider, +live state, baseline, desired state, source/live/merge/provider/ignore +ownership, and declared scope. Product meaning belongs in +`docs/product.md`; exact field and transition semantics belong in +`docs/reference.md`. -## Shan Hai Jing note +## Project note -《山海经·西山经》中的陆吾,负责守护和管理昆仑一方,并“掌管天之九部及帝之囿时”。Luwu 借用的是这种“先守边界、再辨归属”的精神;形象和产品气质可以在后续设计中重新诠释,不把古籍中的形貌直接当作 UI 约束。 +The name Luwu is inspired by the guardian role in the *Shan Hai Jing*. That +image is a project character, not a UI constraint or a product contract. diff --git a/README.md b/README.md index f905ed0..be56f62 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,26 @@ # Luwu -Luwu is an early-stage configuration orchestrator for dotfiles, developer tools, and agent configuration. +Luwu is an early-stage configuration orchestrator for dotfiles, developer +tools, and agent configuration. -It is intended to make configuration drift explainable and repairable without pretending that every difference should be overwritten. Luwu will explore explicit resource semantics, semantic drift, field ownership, controlled reverse sync, and narrow external providers. +It is intended to make configuration drift explainable and repairable without +pretending that every difference should be overwritten. Luwu explores explicit +resource semantics, semantic drift, field ownership, controlled reverse sync, +and narrow external providers. -The project is currently a developer-confidence preview, not a general-use tool. The first vertical slice supports local `.j2` templates and source symlinks: inspect and plan are read-only, and apply requires explicit confirmation. Resource kind is inferred from the source suffix unless explicitly overridden. The implementation is deliberately allowed to grow from validated experiments rather than from a fully predetermined architecture. +The project is currently a developer-confidence preview, not a general-use +tool. The first vertical slice supports local `.j2` templates and source +symlinks: inspect and plan are read-only, and apply requires explicit +confirmation. The implementation is deliberately allowed to grow from +validated experiments rather than from a fully predetermined architecture. ## Try the preview The preview requires Python 3.12+ and uv: -The project fixture lives under `tests/fixtures/m1`. It is used by the isolated CLI E2E check and can be copied to a temporary directory for the manual loop, so `apply` does not modify fixture data: +The project fixture lives under `tests/fixtures/m1`. It is used by the +isolated CLI E2E check and can be copied to a temporary directory for the +manual loop, so `apply` does not modify fixture data: ```text uv sync @@ -22,7 +32,11 @@ uv run luwu apply --manifest "$demo_dir/luwu.toml" --yes uv run luwu inspect --manifest "$demo_dir/luwu.toml" ``` -Read [the current reference](docs/reference.md) for the manifest, CLI, JSON, and safety contract, and [implementation status](docs/status.md) for verified scope. M3b adds explicit single-resource public baseline acceptance and literal-JSON reverse-sync. M3c adds journaled execution of public whole-file resources and read-only recovery observation. Provider integration remains future work. +Read [the current reference](docs/reference.md) for the manifest, CLI, JSON, +and safety contract, and [implementation status](docs/status.md) for the +verified scope. The reference and status documents are the authority for +current capabilities; this page intentionally stays at user-entry-point +level. Run the deterministic test suite with: @@ -32,17 +46,20 @@ uv run --locked python -m unittest discover -s tests -v ## Documentation -- [Agent and maintainer entry point](AGENTS.md) -- [Product seed](docs/product.md) -- [Delivery roadmap](docs/roadmap.md) -- [Current implementation design](docs/design.md) +- [Product direction](docs/product.md) - [Current command and manifest reference](docs/reference.md) -- [M1 milestone closure record](docs/milestones/m1.md) -- [M2/M3 milestone records](docs/milestones/m2.md) and [M3](docs/milestones/m3.md) - [Implementation status](docs/status.md) +- [Current internal design](docs/design.md) +- [Development and release workflow](docs/maintenance.md) +- [Delivery roadmap](docs/roadmap.md) +- [Milestone closure records](docs/milestones/) +- [Agent and maintainer entry point](AGENTS.md) -Future design, reference, maintenance, status, and decision documents will be added only when they have a clear owner and an independent purpose. The documentation map and single-source-of-truth rules are defined in AGENTS.md. +Documentation ownership and single-source-of-truth rules are defined in +`AGENTS.md`. ## Acknowledgements -Luwu is an independent implementation inspired by the concepts and workflow of [Dotter](https://github.com/SuperCuber/dotter). It does not copy or include Dotter's source code. +Luwu is an independent implementation inspired by the concepts and workflow of +[Dotter](https://github.com/SuperCuber/dotter). It does not copy or include +Dotter's source code. diff --git a/docs/design.md b/docs/design.md index 704ef88..5f59ad0 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,10 +1,13 @@ -# Luwu M1/M2/M3a/M3b/M3c/M4 Design +# Luwu Current Implementation Design Status: current implementation design -M1 is a small forward-only vertical slice that tests Luwu's central boundary: a declared configuration relationship can be observed and explained before an explicit mutation. The public details are owned by [reference.md](reference.md); this document explains the current flow and why its limits are intentional. +The public manifest, CLI, JSON, error, and write promises are owned by +[reference.md](reference.md). This document explains the current call graph, +module responsibilities, and implementation mechanisms. It must not become a +second public contract or a historical status log. -## Flow +## End-to-end flow ```text CLI input @@ -15,177 +18,92 @@ CLI input -> explicit confirmation -> complete stale-state preflight -> atomic file replacement - -> fresh post-apply plan + -> fresh post-action observation ``` -`luwu/manifest.py` owns the TOML schema, kind inference, and manifest-root path boundary. `luwu/rendering.py` reads only a declared template source and renders it with a sandboxed Jinja environment, strict undefined variables, no loader, and no network or subprocess capability. `luwu/reconcile.py` owns kind-specific observation, plan metadata, stale checks, and atomic writes for files and symlinks. `luwu/cli.py` translates argparse input and serializes human or metadata-only JSON output. - -The plan keeps rendered bytes in memory only so the apply step can use exactly what was inspected. They are not persisted, printed, hashed into output, or copied into a baseline. Applying a plan first validates the declared target, including no-op observations, so an already-stale target cannot be silently ignored. M1 accepts exactly one resource and therefore does not define a multi-file transaction or rollback contract. Each replacement is atomic, and the existing target remains untouched until the final replacement step. On the supported POSIX path, apply walks the manifest root with descriptor-relative `O_NOFOLLOW` operations, records source/target identities, locks the target directory for cooperating Luwu writers, creates its temporary entry in that held directory, and replaces the target through that directory descriptor. Unsupported filesystem primitives fail closed. An advisory lock cannot constrain an unrelated process that ignores it; M1 therefore does not claim protection against such races, and a stronger kernel compare-and-swap boundary remains future work. - -## Ownership and scope - -M1 supports only `owner = "source"` and `scope = "whole-file"`. That is an explicit limitation, not a generic precedence rule: the declared template or source path owns the complete target path, while anything outside that target is outside the resource. A live-side difference is reported as drift and is never reverse-synced or silently adopted. Field ownership, baselines, merge decisions, and provider values require a later contract. - -## Semantic observation - -For templates, the desired side is always the rendered template. M1 only treats exact byte equality as `in_sync`; without a format adapter, line endings, trailing whitespace, and final-newline differences remain `drifted` and are replaceable. For symbolic resources, the desired side is the source path resolved within the manifest root. All other readable differences are `drifted`. Missing targets and unsafe target boundaries are separate states so the next action is visible. - -This deliberately avoids pretending that a generic formatter or parser can safely preserve every configuration language. Structured comparison and field-level reverse sync are later experiments with their own contracts. M1 template variables are loader-classified public literals; provider references and secret-bearing inputs have no accepted path into rendering. - -## M2 read-only observation - -M2 extends the flow only after manifest validation: - -```text -version 2 manifest - -> stable multi-resource observations - -> explicit comparison adapter - -> metadata-only plan - -> read-only boundary -``` - -The manifest loader rejects cross-resource target conflicts and ancestor overlaps before any resource is planned. The planner then observes every resource in stable name order; a rendering failure becomes a resource-level blocked observation so another resource is not silently omitted. A blocked observation blocks the plan as a whole, but does not prevent the remaining resources from being explained. - -Exact bytes remain the default. The literal `copy` kind reads source bytes without Jinja rendering. The JSON adapter receives rendered template bytes and live target bytes, not Jinja source. It has a deliberately small strict-JSON equivalence relation: it retains all fields and array order, rejects duplicate keys and unsupported syntax, and distinguishes semantic drift from formatting-only representation differences. JSON semantic drift is reported rather than mapped to a write action. - -Version 2 has no apply capability. This is a capability boundary, not a dry-run flag: `inspect` and `plan` are observations, while `apply --yes` is rejected with `m2_read_only` before stale checks or target writes. Multi-resource transaction, rollback, baselines, field ownership, and reverse sync remain M3 responsibilities. - -## M3a field observation - -M3a keeps the M2 read-only boundary and adds one narrow three-way observation: - -```text -version 3 manifest - -> render desired JSON - -> no-follow read live target and explicit baseline - -> classify declared top-level fields by ownership - -> report metadata only -``` - -`luwu/ownership.py` is a pure classifier. It parses desired and live objects with the existing strict JSON rules, validates a closed baseline envelope bound to the resource/source/target and complete field-owner map, and compares each declared top-level field as a whole subtree. Missing fields use a private sentinel so they remain distinct from JSON `null`. A missing baseline produces `unbased` observations and never grants a candidate. A source/live/merge owner only changes the direction of a one-sided candidate; it does not override a conflict. Undeclared desired/live changes are a separate boolean signal and do not expose unknown keys or values. - -`luwu/reconcile.py` reads a baseline through the original declared path with descriptor-relative no-follow operations. It does not use the rendering source resolver for this read, does not create a baseline, and blocks symlinks, non-regular files, missing files, invalid envelopes, and identity mismatches. M3a resources always return `m3_read_only` for apply; candidates are observations and are not translated into `create` or `replace` actions. Persistent plans, multi-resource execution, and rollback belong to the separate M3c contract described below. - -## M3b explicit mutation - -Version 4 keeps the M3a observation path and adds a separate single-resource -mutation path. `accept` builds a new closed baseline envelope from an explicit -desired/live choice and selected fields. `reverse-sync` first requires a -`live_changed` reverse candidate and then patches only an explicitly mapped -top-level key in a literal JSON source. Dynamic Jinja source is rejected; the -live target is never copied wholesale into a template. Both writers use -descriptor-relative no-follow parents, temporary entries, directory locks, -atomic replacement, and a fresh post-write plan. Durable plan records and -multi-resource execution are separated into the version 5 execution slice. - -Field observations retain a private baseline digest calculated from the bytes -actually supplied to the classifier, alongside existing source/live stale -evidence. Reverse-sync reuses that binding in its writer callback; it does not -infer authorization from an independently reread baseline or persist another -snapshot. The callback covers the manifest and baseline around replacement -and post-write verification. Public behavior is defined in [reference.md](reference.md). - -## M3c execution slice - -Version 5 keeps observation and mutation separate while granting a new, -narrow capability to explicit public whole-file resources: - -```text -version 5 manifest - -> stable observations - -> complete source/target/manifest preflight - -> durable planned/preflighted/commit_intent journal - -> one locked atomic writer at a time - -> committed / unchanged / unknown / not-attempted states - -> read-only recover/reobserve -``` - -The execution journal is a closed metadata schema. It binds the manifest -identity, resource order, source and target roles, relative paths, operation, -non-content file conditions, and state transitions; it never persists rendered -bytes, values, diffs, provider payloads, secrets, or source/target content -hashes; the manifest digest is retained only to bind the manifest identity. A -resource is marked committed only after its atomic replacement and directory sync return -success. If the replacement or cleanup boundary is uncertain, execution stops, -records recovery-required state when possible, and never rolls back an earlier -resource. `record-inspect` and `recover`/`record-reobserve` are deliberately -read-only: they inspect or re-observe the recorded boundary, do not replay old -inputs, and do not provide an automatic recovery mutation. - -The journal writer and execution preflight share one deterministic lock-name -function, so the auxiliary write cannot escape path-conflict checks. Recovery -combines existing non-content condition checks with the fresh plan's resource -status when classifying confirmed resources; it adds no persistent content -evidence or recovery engine. - -The executor also retains target progress in memory independently of journal -publication. A single execution error boundary attaches that progress to -`ApplyError`, so a later record or failure-marking error cannot erase known -target replacements. The CLI serializes only the allowed metadata fields and -keeps the readable journal separate from this invocation's target evidence. -This uses the existing writer outcomes and journal, without another durable -ledger or recovery mechanism. The exact error states and recovery aggregation -are defined in [reference.md](reference.md). - -## M4 provider execution - -Version 6 is a separate path from the public version-5 executor: - -```text -version 6 manifest - -> closed schema and external-target boundary - -> explicit runtime authority - -> one bounded rbw lookup per provider declaration - -> short-lived secret render context - -> metadata-only observation - -> complete preflight with the captured bytes - -> owner-only atomic external-target replacement - -> independent secret-safe journal - -> read-only current re-observation -``` - -The manifest declares that subprocess capability is needed, but the CLI or -direct library caller must supply a runtime `ProviderAuthority`. The provider -resolver has one supported adapter, rbw, and one narrow command shape. Its -subprocess runner does not inherit the caller environment, does not use a -shell, does not connect to a network, bounds both pipes, and maps all provider -failure details to fixed safe errors. Executable identity is checked before, -around, and after the run; this is detection for a local TOCTOU threat model, -not a claim of OS-level isolation. - -The renderer receives a sealed `SecretRenderContext`. Only its private -renderer token can open a temporary alias mapping; public variables cannot -occupy the `secrets` namespace. The opened values are cleared after rendering, -and `RenderedTemplate`/error/projection boundaries do not serialize or print -rendered bytes. Reconciliation keeps the captured rendered bytes only in the -in-process plan so a confirmed apply cannot fetch a different value during -its write preflight. - -Provider targets are absolute and outside the manifest/source and operational -state trees. Descriptor-relative no-follow reads and writes reject symlinks, -non-regular entries, unsafe owner/mode bits, and multiple hard links before a -secret is read and again before replacement. A new target is `0600`; an -existing target must remain current-user-owned and owner-only. The boundary -detects, classifies, and fails closed on local races, but cannot prevent a -privileged or otherwise authorized unrelated writer from changing a directory -between checks. - -Version 6 deliberately does not reuse the version-5 persisted content/digest -condition schema. `SecretPlanRecord` contains only public resource labels, -non-content target state, state transitions, and fixed execution contracts. -The cache is a separate explicit metadata diagnostic and has no reconciliation -decision seam. Recovery never replays or writes: without authority it reports -that current provider observation is unavailable; with authority it can report -current convergence, which is not proof of historical secret content. - -## Safety boundaries - -The normative manifest, CLI, error, and write contract is owned by -[reference.md](reference.md); this section does not repeat its field and state -tables. The design consequences are deliberately narrow: M1 remains -single-resource and forward-only, v2–v4 remain observation or explicit -single-resource mutation contracts, and versions 5 and 6 are separate -multi-resource execution capabilities. Automatic recovery mutation, rollback, -and unrelated-writer race guarantees remain outside the verified closure. The -descriptor-relative, no-follow implementation is the mechanism that preserves -both target boundaries described by the reference contract. +The loader validates a declared manifest and creates resource objects. The +planner observes every resource in deterministic order and returns metadata +only. Mutation paths consume a current plan, revalidate the inputs they rely +on, perform one bounded write, and observe the result again. A blocked or +uncertain boundary remains visible instead of being converted into a +best-effort success. + +## Module responsibilities + +- `luwu/manifest.py` owns parsing and validation of the manifest input and the + manifest-root path boundary. +- `luwu/rendering.py` renders only declared sources with a sandboxed Jinja + environment, strict undefined variables, no loader, and no external + capability. +- `luwu/semantic.py` and `luwu/ownership.py` perform pure comparison and + responsibility classification. They do not write or persist configuration. +- `luwu/reconcile.py` coordinates observation, planning, stale checks, writer + calls, execution progress, and post-action observation. +- `luwu/baseline.py`, `luwu/mutations.py`, and `luwu/reverse_sync.py` keep + explicit acceptance and selective source updates separate from whole-file + deployment. +- `luwu/plan_record.py` and the version-specific record code persist closed + metadata about execution boundaries, never configuration content. +- `luwu/providers.py`, `luwu/secrets.py`, and provider cache code isolate the + external capability path from public resources and diagnostics. +- `luwu/cli.py` translates command-line input and projects approved metadata + into human-readable or machine-readable output. + +The reference document owns the exact field names, state values, errors, and +output shapes associated with these responsibilities. + +## Observation and semantic comparison + +The desired side is rendered or otherwise read from the declared source before +it is compared with live state. Exact bytes remain the conservative default. +An explicitly selected comparison adapter can report representation-only +differences separately from semantic differences, but an adapter never grants +write authority. + +The M2/M3 observation paths keep resource-level failures visible while +continuing to explain other declared resources. The field classifier compares +only declared fields, preserves missing values as a private sentinel, and +returns metadata without values. Baselines are read through their declared +path and are never silently created or updated by observation. + +## Mutation and execution + +All writers operate under the existing parent boundary. They stage the new +entry, retain relevant no-follow identity evidence, replace atomically, and +re-observe the target. A replacement-boundary exception is classified from +staged identity where possible; equal content is not used as provenance. +Cleanup, durability, and postcondition uncertainty remain unknown rather than +being guessed away. + +The multi-resource executor completes its full preflight before the first +writer, keeps resource order stable, and retains target progress in memory +independently of journal publication. The journal writer and its lock use the +same path-conflict checks. Recovery re-observes current state and never +replays historical input or rolls back a previous write. + +The implementation deliberately avoids a general transaction engine, a +second durable ledger, or a recovery mutation layer. The public partial +success and recovery meanings are defined in [reference.md](reference.md). + +## Provider and secret path + +The provider path is isolated behind an explicit runtime authority and a +bounded resolver seam. The subprocess adapter uses a fixed argument shape, no +shell, a minimal environment, bounded output, and fixed safe errors. Provider +values are opened only inside a private rendering context and are kept in +memory for the current calculation. + +Secret-target writes use a stricter existing-parent boundary and owner-only +permissions. Provider records, caches, diagnostics, and errors use +metadata-only projections. The confidentiality contract and the supported +provider shape belong to [reference.md](reference.md); this section describes +the separation of implementation paths. + +## Deliberate limits + +The current implementation does not provide automatic replay, rollback, +historical secret-content proof, exact reviewed-plan tokens, network +providers, or strong consistency against writers that ignore Luwu's advisory +locks. These limits are current status and contract facts, not invitations to +silently broaden this design. Future changes need a new owner decision, +evidence, and updated reference/status records. diff --git a/docs/maintenance.md b/docs/maintenance.md index afe63c3..d4a6f2e 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -1,8 +1,10 @@ -# Maintenance and release workflow +# Maintenance and Release Workflow -This document owns the development and release workflow. The versioned manifest, -CLI, JSON, error, provider, secret, journal, cache, and platform contracts are -defined by [reference](reference.md) and [milestone M4](milestones/m4.md). +This document owns the development, documentation, testing, release, and +migration workflow. The versioned manifest, CLI, JSON, error, provider, +secret, journal, cache, and platform contracts are owned by +[reference](reference.md). Milestone records own dated scope and closure +evidence; [status](status.md) owns the current snapshot. ## Local checks @@ -23,14 +25,16 @@ M4 provider tests use an injected resolver or a fake `rbw` executable. They do not access a real vault. The M3 ablation experiments and the M4 ablation are part of the boundary review and must run in temporary directories. -`prek run --all-files` must be run in a checkout whose hook/cache directories -are writable. A read-only shared agent directory is an environment failure, not -evidence that the source or tests passed. +`prek run --all-files` must be run in a checkout whose hook and cache +directories are writable. A read-only shared agent directory is an environment +failure, not evidence that the source or tests passed. An isolated copy is +acceptable when it is byte-checked against the working tree. ## Provider and secret operations -Version 6 provider execution requires an explicit runtime authority for each -invocation: +The commands below are workflow examples, not a second CLI contract. See +[reference](reference.md) for their exact arguments, output, errors, and +security promises. ```text luwu inspect --manifest luwu.toml --allow-subprocess --rbw-executable /absolute/path/rbw @@ -39,10 +43,9 @@ luwu record-inspect --record /absolute/path/journal.json --json luwu recover --record /absolute/path/journal.json --allow-subprocess --rbw-executable /absolute/path/rbw --json ``` -`record-inspect` is read-only. `recover` re-observes and never replays or -rolls back a historical secret. Provider values, references, rendered bytes, -hashes, journal content evidence, and cache values must not be added to logs or -diagnostics. The declared secret target is the only durable secret output. +Provider values, references, rendered bytes, hashes, journal content evidence, +and cache values must not be added to logs or diagnostics. The declared secret +target is the only durable secret output. The cache is an explicit diagnostic facility, independent of reconciliation: @@ -54,10 +57,47 @@ luwu cache-inspect --cache /absolute/path/provider-cache.json --rbw-executable / Inspection, planning, applying, and recovery do not refresh or repair the cache. A cache status cannot authorize a provider or change a plan decision. +## Documentation maintenance + +Before editing documentation, classify the statement: + +1. product intent or value; +1. stable public contract; +1. current implementation fact; +1. internal mechanism; +1. delivery sequence; +1. workflow instruction; +1. dated historical evidence; or +1. review pattern. + +Edit the corresponding owner named in `AGENTS.md`. In every other document, +use a short summary and a relative link. A closed milestone may retain the +decision and evidence that existed at its date, but it must not become a +second current contract. Do not add a translation mirror or a new specialist +document unless it has an independent owner and audience. + +After editing: + +- search for a second definition of each changed field, state, error, or + capability; +- check that summaries link to their owner and do not silently change scope; +- check that current status does not repeat historical logs; +- check that a skill pattern cites code, tests, or a dated closure record; +- run the narrowest relevant documentation and code gates. + +## Pattern maintenance + +Good and bad patterns belong in the relevant `.agents/skills/*/SKILL.md`. +Patterns are review evidence, not contracts. A pattern entry must identify the +observed behavior, evidence, risk, and smallest corrective direction. Promote +it to `product`, `reference`, `design`, `status`, or a milestone owner only +when repeated evidence makes it a stable rule. Do not create a parallel +pattern catalog merely to avoid choosing an owner. + ## Release gates Before release, test a wheel and an sdist in fresh virtual environments. Each -environment must run `luwu --version`, the v1–v6 smoke tests, and the complete +environment must run `luwu --version`, the v1-v6 smoke tests, and the complete test suite without importing from the source checkout. The CI workflow keeps the declared Linux/Python matrix visible and exercises the unsupported-platform branch. Do not claim a platform or Python combination is supported solely diff --git a/docs/milestones/m1.md b/docs/milestones/m1.md index 5c492a4..358f681 100644 --- a/docs/milestones/m1.md +++ b/docs/milestones/m1.md @@ -4,6 +4,10 @@ Status: Closed for functional scope; safety-contract corrections applied This is the closure record for the first vertical slice in the [delivery roadmap](../roadmap.md). Its scope and rationale are fixed after closure; current implementation facts and repository gates belong in [../status.md](../status.md). New behavior belongs to a later milestone. +The checklist below is historical acceptance evidence. The current public +behavior is defined in [../reference.md](../reference.md), not by this +closure record. + ## Goal Let a developer exercise a complete, isolated loop for explicitly declared local template and symbolic resources: diff --git a/docs/milestones/m2.md b/docs/milestones/m2.md index 44e6cd0..335fdde 100644 --- a/docs/milestones/m2.md +++ b/docs/milestones/m2.md @@ -4,6 +4,10 @@ Status: closed for the scoped read-only behavior; repository gates pass. M2 proves that Luwu can observe multiple declared resources and run an explicitly selected semantic comparison without claiming a write contract that has not been defined. +This is a historical closure record. The current comparison, output, and +read-only behavior is owned by [../reference.md](../reference.md); the +checklist below records what M2 accepted at closure. + ## Scope - manifest version 2 with multiple resources ordered by name; diff --git a/docs/milestones/m3-execution-closure.md b/docs/milestones/m3-execution-closure.md index b28b871..6491dd4 100644 --- a/docs/milestones/m3-execution-closure.md +++ b/docs/milestones/m3-execution-closure.md @@ -1,162 +1,71 @@ -# M3 失败结果与冲突边界补齐 - -日期:2026-09-13 至 2026-09-14。状态:实现、独立代码审查与最终验证完成。 - -本轮先执行 `git fetch origin`,确认当前 HEAD 与 `origin/master` 同为 -`d9d7092`,工作树无本地改动。213 项 unittest 和两份既有 M3 消融实验 -通过。新反例说明原回归不足以证明全部冻结契约闭合,因此本轮继续补齐 M3, -M4 仍是 [roadmap](../roadmap.md) 中的后续工作。 - -## 当前证据与计划 - -1. **目标提交事实与 journal 发布事实混淆。** 在目标已完成替换后,最终 - `PlanRecord.write` 于发布前失败,`execute_execution_plan` 抛出的 - `ApplyError.committed` 为 `False`,目标实际已是 desired。反过来,journal - 自身发布成功也不能证明任何目标已经写入。执行器应从实际 writer 进度累计 - 目标事实,所有 journal 失败出口都保留它;API/CLI 不能靠重读 journal - 才知道本次调用已经做过什么。 -1. **恢复的汇总掩盖未执行资源。** 合法 journal 中唯一资源为 - `not-attempted` 时,恢复保留该资源状态,却返回顶层 `confirmed`。 - 仅当所有资源的当前重观察均为 `confirmed`,顶层才可确认;未知和未执行 - 资源继续要求人工处理。恢复仍然只读,不重放、不回滚。 -1. **未选字段的冲突未阻止反向写回。** 同一资源中 `setting` 为 - `conflict/review`,`runtime` 为 `live_changed/reverse_candidate`,选择 - `runtime` 仍能反向写回并返回 `committed`。在 reverse-sync 构建补丁前 - 拒绝资源级 `Status.CONFLICT`,包括由不支持的归属方向产生的 review。 - 不把此 guard 放进 accept 共用入口;显式 baseline acceptance 仍可按用户 - 选择接受 desired/live,保留其原有权限语义。 - -M3a 观察及原 M3b/M3c 功能继续按 [M3 冻结范围](m3.md) 验证,不扩大到 -动态模板反向映射、provider、自动恢复或不合作写入者的强一致性保证。 -没有生产反例和契约依据的候选不作为新增开发项。 - -## 待审接口与开发分工 - -执行失败沿用 `ApplyError`,增加可选的 metadata-only `execution` 上下文。 -它只包含 `plan_id`、`committed`、`changed_targets` 和按计划排序的 -`resources`(每项仅 `name`、`target`、`state`),由执行器固定构造,CLI -按允许字段序列化,不透传任意字典或异常载荷。删除草案中与 error/journal -重复的 `execution.state`。资源状态定义如下: - -- `not-attempted`:尚未进入目标 writer;在 intent journal 失败时仍为此状态。 -- `failed`:已经尝试 writer,但 writer 明确报告未替换目标。这是错误上下文 - 的新增区分,不改变 journal 的四态资源结果或持久 schema。 -- `unknown`:writer 报告已替换但后续持久性、清理或目标验证不能确认; - 不将未知结果升级为成功。 -- `committed`:writer 与目标后置条件已成功确认;之后 journal 失败不降级此事实。 -- `unchanged`:已完成当前 no-op 的处理。 - -`changed_targets` 按计划顺序列出已知发生目标替换的路径,包括 writer 报告 -`committed=True` 后抛错的目标;未进入 writer 或明确未替换的目标不加入。 -`ApplyError.committed == execution.committed == bool(changed_targets)`。 -`PlanRecordError.committed` 继续只表示 journal 发布,与目标事实分离。 -一个外层执行错误边界附加内存上下文,避免各个失败出口重复拼装。 -CLI 失败增加对应 `execution` 对象, -journal 仍单独描述实际可读取的持久记录,不用内存状态伪装成已持久化状态。 -此为 v5 错误输出的增量修正,v1–v4 输出及持久 journal schema 不变。 - -| 包 | 不重叠写集 | 验收 | -| ----------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| A:执行失败事实 | `errors.py` 的可选 execution 上下文;`reconcile.py` 的 execution/write-record/failure helper;独立执行失败测试 | 初始、逐资源、最终 journal 故障;N 成功/N+1 失败;journal 不可读时仍保留每个目标结果;不混淆 journal 与 target commit | -| B:授权与恢复汇总 | `mutations.py` 的 reverse-sync guard;`reconcile.py` 的 recovery 汇总;独立冲突和恢复测试 | preview/确认均阻断未选字段 conflict/review;显式 accept 仍可使用;单独 not-attempted 不误报 confirmed;只读快照保持 | -| C:CLI 失败输出 | `cli.py`;独立 CLI 故障测试 | JSON 与人读输出可见累计目标状态;journal 不可用也能续查;无值、摘要、异常载荷泄漏;旧版本兼容 | -| 主 agent:整合 | 本计划、owning docs、快速消融实验、集成验证 | 汇总独立 review,冻结接口后派发 luna max;审核交界,完成全套回归和仓库 gate | - -A 与 B 在 `reconcile.py` 中仅修改各自函数,开发期间不整文件格式化。 -C 按冻结的 `ApplyError.execution` 接口实现,A 完成后做真实集成测试。 -不引入事务引擎、额外持久日志、通用 provider/状态框架或第二套 recovery。 - -故障矩阵覆盖初始 journal 发布前/后、plan/resource preflight、plan intent、 -no-op 记录、resource intent、writer 替换前/后、目标后置条件、resource commit -记录、failure marking 自身失败及最终 plan commit 记录。分别断言真实目标、 -内存上下文、实际可读 journal;全 no-op 的最终日志失败也必须保持 -`committed=False`。恢复覆盖 standalone not-attempted API/CLI,授权覆盖 -未选真实冲突、未选错误方向 review、合法 forward/reverse 并存及显式 accept。 - -## 审查与消融顺序 - -由不同 sol medium agent 从逻辑、授权/归属/语义、保密/文件边界/可验证性 -审查本草案。主 agent 汇总采纳或拒绝理由,冻结必要契约。 -随后用真实生产执行器、writer、恢复入口及临时目录运行短小探针: - -- 去掉执行器累计事实:应重现最后一次 journal 失败时的假 `committed=False`; - 增加同一 journal 的内存异常上下文应足够,不需要第二份持久 ledger。 -- 去掉“全部资源已确认”的汇总条件:应重现单独 not-attempted 的假确认; - 只读结果汇总即可修复,不需要恢复引擎。 -- 去掉资源级 conflict guard:应重现未选字段冲突时仍反向写回; - 一个现有状态检查即可,不需要通用策略 registry。 - -消融证明方案取舍,生产故障注入回归证明最终实现。开发完成后再由独立 -reviewer 检查实现,主 agent 逐项核验 API/CLI、零写入、部分成功、保密、 -兼容、文档以及仓库 gate,未通过项不标完成。 - -## 主 agent 审查汇总 - -三个独立 sol medium agent 分别审查逻辑/可验证性、授权/归属/语义、保密/ -文件边界。三项反例均有当前生产代码证据,纳入补齐;保留 M3a implemented, -本轮初始 M3b/M3c 为 partial。 - -采纳两组共同建议,删除重复且含义不清的 `execution.state`;采纳逻辑审查的 -`failed` 区分,避免把明确未替换的失败写成 unknown 或未尝试。保留逐资源 -target/state、changed_targets 和 plan_id,分别承担续查位置、部分结果、 -已发生替换及日志关联。拒绝第二份持久 ledger、通用事务/策略 registry。 - -冲突检查复用现有 `Status.CONFLICT` 聚合语义;不再复制一套逐字段 review -规则。accept 是显式接受比较点的独立动作,不共用此新增阻断。 -恢复仅收紧当前结果的汇总,不叠加顶层 journal 状态策略,也不加入自动重放。 -NOOP 的非协作外部写入竞态属于冻结范围外,未作为本轮功能缺口。 - -## 消融结果 - -开发前运行 `uv run experiments/m3_execution_closure_ablation.py`:四个生产 -操作探针通过。初始 journal 已发布但目标未写、最终 journal 未发布但目标已写 -这两个相反场景,均证明 journal publication 无法替代累计目标事实。单独 -not-attempted 和未选字段冲突分别在删除对应 guard 后重现假成功与未经当前 -冲突审查的反向写入。最小方案没有第二持久 ledger、恢复引擎、策略 registry -或重复的 execution 总状态;原有 journal schema 保持不变。 - -此实验使用真实执行器和 writer 加短小候选 wrapper,仅证明设计取舍;完整 -时序、失败标记故障、部分提交和 CLI 保密以随后生产实现回归为准。 - -实现阶段继续做等价收敛:删除仅包装三个局部变量的 `_ExecutionContext` -类型及其转发方法,复用一个外层错误边界构造固定元数据;合并 writer 返回 -未提交与抛出明确未提交异常的相同失败处理。既有状态、归属聚合和 journal -继续承担各自职责,没有新增持久类型或事务抽象。 - -## 实现分工与终审 - -三个 luna max agent 按 A/B/C 写集完成执行器、授权/恢复和 CLI;模型容量 -中断后,另一个 luna max agent 接续补齐测试矩阵及类型修正。主 agent 负责 -交界审查、文档、消融和最终集成。 - -独立 sol medium 终审确认三项生产修复逻辑成立,保密/文件边界没有剩余 -阻断。终审要求补齐 plan/resource preflight journal 的直接故障注入,并在 -最终 gate 后统一状态文档;这些验收项不以先前的绿测替代。 - -## 完成审计 - -| 要求 | 当前证据 | 结论 | -| ----------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------- | -| 先同步最新基线 | `git fetch origin` 后 HEAD 与 `origin/master` 均为 `d9d7092`,差异 0,无需快进 | verified | -| M3a 冻结观察契约 | manifest、ownership、严格 JSON 与只读观察的既有回归继续通过 | implemented | -| M3b 冲突审查边界 | `test_m3_conflict_recovery.py` 覆盖未选冲突/错误方向、preview/confirm 零写、合法双向候选及显式 accept | implemented | -| M3c 目标提交事实 | `test_m3c_execution_outcomes.py` 覆盖完整 journal 阶段、writer 前后、后置条件、failure marking、raw cleanup 和全 no-op | implemented | -| M3c 恢复汇总 | standalone not-attempted 的 API/CLI 回归返回 recovery_required,全树快照不变 | implemented | -| CLI 保密及续查信息 | `test_m3c_execution_outcomes_cli.py` 验证闭合元数据、部分成功、journal 损坏/存在性未知及旧版本兼容 | verified | -| 独立审查与消融 | 三路 sol medium 计划审查,授权/逻辑/保密终审;四个新增消融探针与两份既有实验通过 | verified | -| 解耦开发与主 agent 整合 | 三个 luna max 包及中断后的 luna max 收尾;主 agent 汇总并删除重复总状态和薄包装 | verified | -| 全套验证 | 243 项 unittest、Ruff、ty、compileall、uv lock、wheel/sdist 构建、diff check 及完整 hooks | verified | - -新增 30 项测试,其中参数化故障注入进一步覆盖多个 journal 阶段。终审要求的 -plan/resource preflight 直接故障、当前目标已替换时 failure marking 再次失败, -以及 journal 存在性检查抛错均已补齐。存在性无法确认时输出 null,不伪装成 -不存在;稳定输出语义只在 [reference](../reference.md) 定义。 - -完整 hooks 在 `/tmp/luwu-m3-closure-gate-MJnGeL` 的逐文件一致副本中通过, -包括所有新增未跟踪文件;原工作树受保护的技能文件和 Git 索引未修改。 -初次构建/脚本依赖解析因沙箱 DNS 失败,获准重试后通过,不将首次失败记为通过。 -构建产物位于 `/tmp/luwu-m3-execution-closure-dist/`;隔离 M1 E2E 位于 -`/tmp/luwu-m3-closure-e2e-rvznvC`,最终 in_sync、普通文件权限 0644、无临时残留。 - -M3 在原冻结范围内完成;M4 本轮未启动。未 commit、push 或改变原工作树的 -分支策略;运行探针没有修改真实用户配置。 +# M3 Execution and Conflict Closure + +Date: 2026-09-13 to 2026-09-14. Status: implementation, independent review, +and final verification complete. + +This is a historical closure record for the execution and conflict repairs. +The current public behavior is owned by [reference](../reference.md), and the +current implementation snapshot is owned by [status](../status.md). + +## Review findings + +The execution review identified three failures that the earlier 213-test +baseline did not cover: + +1. Target replacement facts could be confused with journal publication facts. +1. A journal containing only `not-attempted` resources could be summarized as + confirmed. +1. Reverse sync could proceed with a selected live candidate while another + unselected field required conflict review. + +M4 remained a later roadmap item. The repair did not expand M3 into provider, +secret, automatic recovery, or unrelated-writer consistency work. + +## Accepted repair shape + +The implementation added a metadata-only in-memory execution context to +preserve `plan_id`, known committed targets, and ordered resource states even +when journal diagnostics fail. The journal remains the record of persisted +facts; in-memory execution evidence is not presented as a durable record. + +Recovery now requires every resource to be currently confirmed. Unknown and +not-attempted resources continue to require recovery. Reverse sync rejects a +resource-level conflict or unsupported ownership direction before building a +patch, while explicit baseline acceptance remains a separate action. + +The stable state names, error meanings, and public JSON shape are maintained in +[reference](../reference.md). The descriptions here explain why the repair +was made, not how callers should interpret a current response. + +## Historical implementation slices + +| Slice | Write set | Acceptance focus | +| -------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| Execution facts | `errors.py`, selected `reconcile.py` helpers, execution tests | Preserve target outcomes across initial, per-resource, and final journal failures | +| Authorization and recovery | reverse-sync guards, recovery aggregation, focused tests | Block unselected conflicts and do not confirm standalone not-attempted resources | +| CLI failure projection | `cli.py`, CLI tests | Expose metadata-only cumulative outcomes without values or exception payloads | +| Integration | Plan, owning documents, ablations, and repository gates | Check all boundaries together without adding a second ledger or recovery engine | + +The historical packages were integrated by a main agent. Their write sets are +not a permanent scope system. + +## Review and ablation evidence + +Independent logic, consent, ownership, semantic, confidentiality, boundary, +and verifiability reviews found production counterexamples. Four focused +ablation probes reproduced the false-success outcomes when the relevant guard +was removed. Production fault injection then covered journal phases, partial +success, replace-before/after failures, cleanup uncertainty, CLI redaction, +old records, and read-only recovery. + +The repair retained the existing journal schema and state model. It rejected a +second durable ledger, a general transaction engine, a policy registry, and +automatic replay or rollback. + +## Closure evidence + +The historical closure added 30 tests. The full 243-test suite at that +checkpoint, three M3 ablations, static checks, package builds, an isolated M1 +CLI loop, and the complete isolated hook gate passed. The detailed commands, +temporary artifact paths, and environment notes remain in this record so that +the current status page does not become a duplicate log. diff --git a/docs/milestones/m3-followup.md b/docs/milestones/m3-followup.md index de16397..06e4997 100644 --- a/docs/milestones/m3-followup.md +++ b/docs/milestones/m3-followup.md @@ -1,98 +1,74 @@ -# M3 当前工作树复核与补齐计划 - -日期:2026-09-13。状态:计划经审查与消融后完成开发及验证。 - -本轮重新核验 [M3 冻结范围](m3.md),不沿用旧分支的完成结论。 -初始工作树干净;190 项 unittest 通过,原 M3 消融实验的 13 个参考场景通过。 -这些结果不覆盖新发现的边界反例。当前优先补齐 M3;M4 仍按 -[roadmap](../roadmap.md) 保持后续方向,不在 M3 修复中引入 provider。 - -## 冻结修复计划 - -1. journal 的写入范围必须包含固定锁文件:在创建任何 journal/lock 前, - 拒绝二者与 manifest、source、target 的相同路径、解析别名及祖孙重叠。 - 复用现有路径判定,仅集中锁文件命名,保留已有 CAS 与进程锁。 -1. planner 在既有观察结果的私有内存字段中绑定实际参与分类的 baseline 摘要, - 不将摘要写入输出或 journal;持锁后、replace 前后及最终验证时通过一个 - 回调复核 baseline 与 manifest。提交前变化报 - `stale_plan`,提交后变化保留 committed/unknown 语义。复用既有 live 检查。 - 不新增持久快照、内容日志或通用事务框架。 -1. 为确认的反例增加真实临时目录回归和 CLI 元数据断言;复核没有旁路写入、 - 配置值泄漏和错误的成功状态。 -1. recovery 的已提交/未变化资源,必须同时满足路径条件与 fresh plan 的 - `in_sync` 才能确认;不能同时输出 `confirmed` 和 `drifted`。未知资源只有 - 同样满足当前观察时才标记 `matches_postcondition`,不自动升级为已提交。 - -## 审查、消融与开发顺序 - -由独立 sol medium agent 分别审查契约逻辑和保密、授权、文件边界、可验证性。 -主 agent 汇总可复现反例与建议,再用生产代码探针验证:删除新 guard 是否重新 -出现反例;移除通用 registry、事务及存储抽象是否仍可满足验收。 -只保留有反例支撑的边界,不用纯模型实验替代集成测试。 - -计划冻结后由不同 luna max agent 实现互不重叠的包: - -| 包 | 写集 | 验收 | -| ------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------ | -| A:journal 写入范围 | `plan_record.py`、独立 execution 测试 | 冲突在任何持久写入前阻断,正常执行与 CAS 保持有效 | -| B:反向同步输入绑定 | `mutations.py`、`reconcile.py` 的观察字段与字段 planner、独立 mutation 测试 | baseline/manifest 陈旧状态阻断,提交后失败不误报未写入 | -| C:恢复结果一致性 | `reconcile.py` 的 recovery 分类、独立 recovery 测试 | 同元数据的实际内容漂移不误报 confirmed;恢复保持零写入 | -| 主 agent:集成 | `reconcile.py` 的 journal 路径预检、文档、消融脚本、CLI 集成测试 | 汇总 review、全套回归、hook gate 与完成逐项审计 | - -未证实的候选不作为完成缺口,也不据此添加实现。正式冻结决策、消融结果和验证 -证据在本文件补记;稳定契约只修改其 owner `docs/reference.md`,当前状态只修改 -`docs/status.md`。 - -## 本轮 review 汇总与消融结果 - -两个独立 sol medium 审查分别从契约逻辑与保密/授权/文件边界/可验证性出发, -均真实复现两个阻断:固定锁文件提前创建 0 字节 target;baseline 已变化后仍 -反向写入并返回 `committed`。初始成熟度为 M3a implemented、M3b/M3c partial。 - -采纳两组共同建议:锁文件与 journal 使用同一命名来源,冲突报 -`record_path_conflict` 并保持所有文件快照。后续对抗审查发现分类前后夹读还可能 -遭遇 A→B→A:分类读取 B,却把授权绑定到 A。因此改为由 planner 绑定实际分类 -输入的私有摘要,复用 source/live 既有模式,不新增 snapshot 类型。 -manifest 已有外层检查,但临时文件写入期间仍 -存在可注入的检查间隙,因此复用回调将其与 baseline 一起覆盖提交前后。 - -在开发前运行 `uv run experiments/m3_followup_ablation.py`:两个最小 guard -均阻断反例;分别删除 guard 后均重现未经当前授权的写入。探针调用真实生产 -writer,仅以短小 wrapper 实验新增检查;不使用 registry、事务、持久快照或 -snapshot 类。它证明最小方案可行,不替代随后覆盖 writer 内时序的生产回归。 -原 `m3_ablation.py` 的 13 个参考场景及各删除反例也重新通过。 - -后续保密/可验证性审查又复现 recovery 同时报告 `confirmed` 与 `drifted`:原地 -改变 target 为同长度内容并恢复 mtime,既有非内容条件无法区分,而 fresh plan -已经发现漂移。新增第三个消融探针证明利用已有 plan 状态即可阻断误报;删除该 -条件则重现,仍不需要持久内容摘要或 recovery engine。此项作为独立 C 包开发。 - -第三项也由另一 sol medium agent 独立复核:综合判定需当前 `in_sync`,路径级 -布尔值继续仅表示非内容条件。采纳其证据边界意见:确认不能证明历史字节未变, -具体限制只写入 reference。C 包由完成 A 的 luna max agent 接续,B 与 C 并行。 - -实现后的调用点检查又确认 `_write_source` 的旧三个 live 参数与条件分支已无 -调用者:统一输入回调承担同样检查。因此将回调设为必需参数,删除旧分支, -再运行既有 live 竞态回归验证等价;不为了内部兼容保留无用接口。 - -## 完成审计 - -| 要求 | 当前证据 | 结论 | -| -------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------- | -| M3a 原冻结观察契约 | 原有 manifest、ownership、M3 观察测试继续通过 | implemented | -| M3b 当前授权绑定 | `test_m3b_input_binding.py` 覆盖分类实际输入、ABA、baseline缺失/不安全、manifest变化与提交后结果 | implemented | -| M3c journal 写入范围 | `test_m3c_record_paths.py` 覆盖声明角色、别名及祖孙重叠,CLI另证实缺失目标未被锁创建 | implemented | -| M3c recovery 一致性 | `test_m3c_recovery_coherence.py` 覆盖 committed/unchanged/unknown 的内容漂移、正常收敛和 not-attempted;unknown 不升级确认 | implemented | -| 输出与副作用边界 | `test_m3_followup_cli.py` 的错误码、已提交未知状态、零写入和摘要/值不泄漏断言 | verified | -| 多视角计划与代码审查 | 独立 sol medium 逻辑及价值 review,主 agent 汇总;最终组合 review 无剩余阻断 | verified | -| 消融后解耦开发 | 两个 luna max agent 分别承担 A/C 与 B;主 agent 集成,删除无调用者的三组 live 参数/分支 | verified | -| 完整回归及交付检查 | 213 项 unittest、两份消融实验、Ruff、ty、compileall、uv lock、构建及 hooks | verified | - -新增 23 项测试。所有运行数据使用临时目录,未写真实用户配置,也未 commit、push -或变更分支策略。构建产物位于 `/tmp/luwu-m3-followup-dist/`。hooks 对新增未跟踪 -文件使用显式 `--files`,不把 `-a` 误当作包含新文件。当前实现状态与验证环境说明 -由 [status](../status.md) 维护,恢复的证据限制由 [reference](../reference.md) 维护。 - -最终全仓 gate 在包含当前全部 tracked/untracked 文件的临时副本中运行,避免 -文件修正 hooks 打开原工作树受保护的 `.agents/skills`;原工作树和暂存区不受 -影响。副本路径为 `/tmp/luwu-m3-gate-8cZp1I`,逐文件内容一致性另行核对。 +# M3 Follow-up: Current Worktree Review and Repairs + +Date: 2026-09-13. Status: implementation and verification complete. + +This document is a historical review and repair record. The current contract +is owned by [reference](../reference.md), and the current implementation +snapshot is owned by [status](../status.md). The follow-up rechecked the +[M3 frozen scope](m3.md) instead of carrying forward an earlier completion +claim. + +## Trigger + +The initial worktree had 190 passing unit tests and the original M3 ablation +scenarios, but the review found three untested boundaries: + +- creating a fixed journal lock could create a declared target before + execution; +- reverse sync could write after the baseline used for classification had + changed; +- recovery could report `confirmed` while a fresh plan reported drift. + +M4 remained future work during this repair. + +## Frozen repair plan + +The repair kept the existing narrow architecture: + +1. Check the journal and its lock together against manifest, source, target, + aliases, and ancestor relationships before either persistent file is + created. +1. Bind the planner to the baseline bytes actually used for classification. + Recheck that private authorization evidence around the source write and + preserve committed or unknown outcomes after a post-write change. +1. Add real temporary-directory regressions and metadata-only CLI assertions + for the counterexamples, including zero-write and redaction behavior. +1. Require committed, unchanged, and unknown recovery results to agree with a + fresh plan. A standalone `not-attempted` resource cannot produce an overall + confirmation. + +The public meaning of the resulting states is maintained in +[reference](../reference.md), not in this historical plan. + +## Review and ablation + +Independent logic, confidentiality, consent, boundary, ownership, semantic, +and verifiability reviews reproduced the lock-path and stale-baseline +failures. A later review reproduced the recovery aggregation failure. The +minimal ablation probes removed each guard in turn and reproduced the +corresponding bad outcome. The probes used the real writer path, temporary +directories, and no user configuration. + +The implementation deliberately did not add a registry, transaction engine, +persistent snapshot, or generic recovery layer. Existing writer checks and +private in-memory evidence were sufficient. + +## Historical slice boundaries + +| Slice | Write set | Acceptance | +| -------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| Journal path boundary | `plan_record.py` and execution tests | Conflict is rejected before persistent writes; normal CAS behavior remains valid | +| Reverse-sync input binding | `mutations.py`, selected `reconcile.py` planner paths, mutation tests | Baseline/manifest changes block authorization; post-write changes retain honest outcomes | +| Recovery aggregation | `reconcile.py` recovery paths and recovery tests | Content drift is not misreported as confirmed; recovery remains read-only | +| Integration | Journal preflight, documentation, ablation, and CLI integration tests | Cross-slice boundaries and full repository gates are checked | + +These write sets were for one historical implementation pass. They are not a +permanent subagent or agent-scheduling policy. + +## Completion evidence + +The repaired worktree added 23 tests. The follow-up suite, the M3 ablations, +static checks, build checks, isolated hooks, and the temporary M1 CLI loop +passed at closure. Exact commands, test counts, artifact paths, and hook +environment details are retained here as historical evidence rather than +copied into [status](../status.md). diff --git a/docs/milestones/m3-repair-plan.md b/docs/milestones/m3-repair-plan.md index bb35140..4292b5e 100644 --- a/docs/milestones/m3-repair-plan.md +++ b/docs/milestones/m3-repair-plan.md @@ -1,102 +1,66 @@ -# M3 冻结契约补齐计划 - -状态:complete,基于 `83ca72e` 的当前工作树修复与最终 gate;已吸收四份独立逻辑/价值审查 - -## 决策门 - -初始决策不能进入 M4:M3a 的 v3 只读三方观察已实现;M3b 和 M3c 虽然主链路已经接通,但仍有冻结契约内的边界缺口,因此先完成本计划。修复及全部 gate 已通过,M3b/M3c 现为 `implemented/complete`;M4 的 provider、secret、持久化/缓存、能力和平台工作保持 `unstarted`,不在本计划中提前实现。 - -初始审查证据包括: - -- `src/luwu/reverse_sync.py:38-89` 将完整 source 对象重新编码,未选字段的空白、转义、数值词法和布局可能被改写,而预览只列选中字段; -- `src/luwu/mutations.py:435-459`、`src/luwu/baseline.py:226-268` 和 `src/luwu/reconcile.py:2442-2484` 在 `os.replace` 返回后才标记提交,无法覆盖“替换已发生但调用边界抛错”; -- `src/luwu/plan_record.py:444-560` 只封闭对象键,仍接受空资源和任意非空 `condition.type`; -- 当时 243 项 unittest 与三份既有消融实验通过,但没有覆盖上述反例。 - -最终实现证据包括: - -- `reverse_sync.py` 已改为 literal-JSON 顶层成员的局部 span 补丁,预览输出 `replace/add/delete` 和 separator 元数据,不携带值或 diff; -- baseline、M3b source、M3c target 三个 writer 都在 `os.replace` 边界使用 staged no-follow identity,等值独立目标不会进入 `changed_targets`; -- `PlanRecord` 在 create/from_dict/read/inspect 共用非空、连续 ordinal、闭合 condition 值域校验; -- 全量 unittest 274 项通过,四份 M3 消融、Ruff、ty、compileall、lock/build、临时 M1 CLI 和隔离完整 prek gate 均已通过。 - -## 冻结的补齐要求 - -### A:literal-JSON reverse-sync 的实际写入范围 - -`reverse-sync` 只能改变明确选中的顶层字段值,以及为选中字段增删所必需的局部分隔符。未选中的 `source`、`live`、`merge`、`ignore` 字段和未声明成员的 key 顺序、转义、数字词法、空白和末尾换行必须逐字节保留。严格 JSON、动态 Jinja、嵌套路径和 alias mapping 仍然拒绝;无法安全定位/补丁化的输入必须在写入前返回 `reverse_sync_unsupported`,且预览不得虚报较小的 blast radius。 - -实现只需要一个 reverse-sync 内部的顶层成员 span 扫描和局部补丁,不引入通用 formatter、通用 JSON 编辑器、span dataclass、schema registry 或第二套语义比较器。现有 `parse_public_object` 仍负责严格值校验;补丁器负责按解码后的唯一 JSON key 绑定成员,保留 source 字节并替换选中的 value span。选中 key 已存在时记录 `replace`;仅 live 有该 key 时记录 `add`;仅 source 有该 key 且 live 删除时记录 `delete`。首项、中间项、末项、唯一项和空对象的分隔符调整必须是封闭的 preview 元数据 `changes`,只包含 key、操作类型和是否调整 separator,不包含值、原文或 diff;扫描结果与严格解析的唯一 key 集合不一致(包括重复解码 key)即在写入前拒绝。 - -### B:三个 writer 的 replace 不确定性 - -baseline、M3b source 和 M3c target writer 必须对 `os.replace` 抛错后的状态重新观察 held parent 下的目标。三类 writer 共享同一逻辑矩阵,但不新增跨 writer 的事务/结果类:内部结果只有 `not_replaced`、`replaced`、`indeterminate` 三态。 - -- writer 在 replace 前记录临时项的 no-follow `(st_dev, st_ino)` 及 link/file 类型。抛错后只有目标 no-follow identity 等于该 staged identity 且临时项已消失,才可认定 `replaced`;这表示目标已继承 staged entry,但目录持久化/后续校验仍是 unknown。仅目标内容、link target 或语义值等于新值,即使临时项消失,也不能证明 Luwu 的替换发生,必须是 `indeterminate`,防止把外部等值写入加入 `changed_targets`。 -- 目标仍持有旧 identity 且临时项仍持有原 staged identity,可认定 `not_replaced`;旧值/新值相同、临时项消失但 identity 不匹配、父目录不可观察、两边均不可确认或清理/同步二次失败,均为 `indeterminate`,不得猜测提交事实。 -- `not_replaced` 对 mutation 使用 `committed=false`、`outcome=not_committed`;`replaced` 在 replace 已返回时使用 `committed=true`,后续 durability/校验失败使用 `committed_state_unknown`;`indeterminate` 使用 `committed=false`、状态不确定的专用错误码/结果,不得加入 `changed_targets`。 -- M3c 的 `indeterminate` 必须传播为当前资源 `unknown`、总体 `recovery_required`、后续资源 `not-attempted`;只有明确 `not_replaced` 且此前没有已知提交时才是 `execution_failed`。`changed_targets` 只包含 identity 已确认替换或 replace 已成功返回的目标。 -- 若替换已消耗临时项,清理逻辑不得把 `FileNotFoundError` 二次改写成 cleanup-only 结果;`unlink`、unlock、close 等二次故障不得把已确认 `replaced` 或 `indeterminate` 降级为 `not_replaced`。 - -M3c 继续 `on_failure = stop`、`rollback = never`;未知资源之后的资源必须保持 `not-attempted`。不新增事务引擎、自动重放、rollback 或不合作 writer 的强一致性承诺。 - -### C:PlanRecord closed value domain - -在 `PlanRecord.create/from_dict/read` 和 `inspect_execution_record` 共用的校验路径中: - -- resources 非空,ordinal 必须为 `0..N-1`,`next_ordinal == N`; -- `condition.type` 仅允许当前执行器实际使用的 `missing`、`unsafe`、`regular`、`symlink`、`other`; -- 所有数值严格拒绝 bool;`mode` 限于 `0..0o777`,`size/file_id >= 0`,`mtime_ns` 允许有符号整数;`missing`/`unsafe` 的条件值保持全零,regular/symlink 的 `mtime_ns/file_id == 0` 继续表示现有的通配 postcondition; -- 不改变现有 record schema version、状态转移、metadata-only 和 no-follow 持久化边界。 - -三态与公共执行边界固定如下,避免 B/C 各自解释: - -| writer 事实 | `ApplyError`/`MutationError` | `changed_targets` | 资源/计划状态 | -| ---------------------------------------- | ----------------------------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `not_replaced` | `committed=false`,mutation 为 `not_committed`;target 为普通写失败 | 不追加 | journal 当前资源为 `unknown`(schema 没有 `failed`);同次执行的 error context 为 `failed`;无前序提交时计划 `unknown`/`execution_failed` | -| `replaced`,但 durability/后置校验不确定 | `committed=true`,状态不确定 | 追加已确认目标 | 当前资源 `unknown`,计划 `recovery_required` | -| `indeterminate` | `committed=false`,target 使用 `recovery_required`;mutation 使用状态不确定 outcome | 不追加 | 当前资源 `unknown`,计划 `recovery_required` | -| 后续资源 | 不调用 writer | 不变 | `not-attempted` | - -执行错误的 `committed` 表示“是否存在已知替换”,不表示总体是否需要恢复;`recovery_required` 由资源状态和 journal 事实共同决定。C 必须只在 `reconcile.py` 内接通该传播,不临时改动 `errors.py` 或 `cli.py` 的公共 schema;若实现证明必须扩展公共字段,先在切片结果中报告理由并由主 agent 单独整合。 - -## 解耦开发切片 - -各 agent 只修改自己列出的生产文件和新测试文件;不得编辑其他切片的文件、提交或推送。 - -| 切片 | 写入范围 | 验收重点 | -| -------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| A | `src/luwu/reverse_sync.py`、`tests/test_m3b_selective_patch.py` | 选中 value 改变/新增/删除;未选和 undeclared 字节逐字节保留;semantic escaped key/嵌套值/首中末分隔符;非严格/动态输入零写入;preview `changes` 范围准确且不泄露值 | -| B | `src/luwu/baseline.py`、`src/luwu/mutations.py`、`tests/test_m3b_replace_boundary.py` | baseline 与 source 的真实 replace-then-raise、staged identity 三态、旧值相同/等值外部写入/不可观察/cleanup 二次故障,已有 stale/parent 回归不退化 | -| C | `src/luwu/reconcile.py`、`tests/test_m3c_replace_boundary.py` | target 的真实 replace-then-raise、三态传播、`ApplyError.execution`、JSON/human CLI、journal resource state、recover、changed target 与后续 not-attempted 一致;不改公共 schema | -| D | `src/luwu/plan_record.py`、`tests/test_m3c_record_schema_closure.py` | condition 枚举/值域、非空/连续 ordinal、直接库构造到 read/inspect 的一致拒绝 | -| 主 agent | `experiments/m3_final_closure_ablation.py`、owning docs、集成修正 | 先做消融,再审查/合并各切片,维护 `docs/status.md`、`docs/reference.md` 与 closure 记录;D 通过 schema 后再让 C 接入最终状态矩阵 | - -## 验证与消融顺序 - -1. 计划审查后运行快速消融:只保留三个 guard-on/off probe——A 的字节 span 保留、B/C 的 staged identity 重新观察、D 的闭和值域校验;每个删除都必须重现一个当前反例。脚本只使用临时目录和 monkeypatch,不读取或写入用户配置;完整的 baseline/source/target 故障矩阵留在生产回归测试。 -1. 各切片返回后主 agent 检查 diff、结构和切片边界,处理必要的最小交界整合;不接受只增加包装类、通用 registry、第二份状态或与三个反例无关的抽象。 -1. 专门故障注入必须使用真实 writer 链路,让 `os.replace` 完成替换后再抛错,并覆盖 baseline/source/target 的 replace 前失败、replace 后抛错、等值独立目标、staged identity、postcondition/fsync/cleanup 不确定。target 至少三资源:N 已知提交、N+1 `indeterminate`、后续 `not-attempted`;同时断言磁盘事实、公共异常、JSON/human CLI、持久 journal、`record-inspect` 和只读 `recover`。 -1. 保留由 `83ca72e` 生成的 v5 journal fixture,回归 `from_dict`、`read`、`inspect_execution_record`、`recover`,并显式回归 v1-v4 行为;direct-library `PlanRecord` 构造、`update_path_condition` 和 CLI 读路径必须共用同一 schema 校验。 -1. 运行 `PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -B -m unittest discover -s tests -v`,三份既有 M3 消融和新的最终消融;再运行 Ruff check/format、ty、compileall、`uv lock --check`、wheel/sdist build、`git diff --check`、隔离完整 hooks 和临时目录 M1 CLI E2E。最终 closure 记录每项 gate 的 HEAD、命令、退出码、测试数、隔离副本一致性和产物路径,并标为 `passed/failed/blocked/unrun`;历史 status 中的通过记录不复用。 -1. 只有所有新反例有回归且完整 gate 实际通过后,才把 M3b/M3c 和总 M3 状态恢复为 `implemented/complete`。完成声明必须同时写明:`--yes` 针对的是重新计算后的当前 plan,不是此前 preview 的 exact reviewed-plan consent。 - -## 不属于本计划 - -provider/rbw、secret-aware 输入、缓存或 secret baseline、网络/子进程能力、平台扩展、自动 rollback/replay、历史内容证明、用户实际审阅 plan token,以及对忽略 advisory lock 的外部 writer 提供强一致性。这些保留给 M4 或产品后续明确契约。M3 完成不宣称 exact reviewed-plan consent,也不宣称能证明 replace 抛错前后的历史调用事实;只能按上述 identity/journal 边界诚实报告当前状态。 - -## 审查结论与裁剪 - -四份独立审查均要求先改计划再开发,确认 A 的字节保留、B/C 的 replace 后观察和 D 的 closed value domain 均不可消融。已采纳的增补是 staged identity、防等值外部写入误判、undeclared 字节矩阵、preview 编辑类型、semantic key 绑定、真实 CLI/journal/recover 验证、旧 v5 fixture 兼容证据和 gate 证据账本。已裁剪的冗余是统一 replace transaction/result class、通用 JSON formatter/editor/AST、span dataclass、schema registry、第二 ledger、自动 recovery engine 和跨 writer 状态抽象。 - -## 最终 closure 证据 - -验证基线为工作树父提交 `83ca72e`;直接查询 `origin/master` 返回同一提交,沙盒内 `git fetch origin` 因共享 bare repo 的 `FETCH_HEAD` 写权限被阻塞。验证没有依赖历史 status 的通过声明。 - -- 全量:`PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -B -m unittest discover -s tests -v`,274 tests,exit 0; -- 消融:`m3_ablation.py`、`m3_followup_ablation.py`、`m3_execution_closure_ablation.py`、`m3_final_closure_ablation.py` 均 exit 0;其中缺失依赖的 `uv run` 在授权外部网络重试后通过; -- 静态/构建:Ruff check、Ruff format check、`ty check src tests`、compileall、`uv lock --check`、wheel/sdist build、`git diff --check` 均 exit 0;构建产物位于 `/tmp/luwu-m3-dist.fHihxw/`; -- CLI:临时 M1 fixture 的 `plan -> apply --yes -> inspect` 通过,目标为 regular `0644`、内容正确且无 symlink/temporary entry; -- hook:`/tmp/luwu-m3-gate-submit.7jHFAv` 的完整固定 hook 集合 exit 0,精确复制的 tracked/unignored files 逐文件 byte check exit 0。 - -因此本计划关闭,M3b/M3c 和总 M3 状态为 `implemented/complete`;M4 仍保持 `unstarted`。 +# M3 Frozen-Contract Repair Plan + +Status: closed. The repaired v3/v4/v5 implementation and final gate were +completed from the historical `83ca72e` worktree. + +This record captures the boundary decisions that closed the M3 repair. It is +not a second public contract. Current behavior is defined in +[reference](../reference.md); current status is defined in +[status](../status.md). + +## Gaps that blocked closure + +The initial implementation had three evidence gaps: + +- literal-JSON reverse sync could re-encode more source bytes than the selected + fields justified; +- a replace call that changed the target before raising could be misclassified + from equal bytes rather than staged identity; +- the journal record accepted values outside the executioner's closed + condition domain. + +## Accepted repair decisions + +The repair retained three small guards instead of introducing general-purpose +abstractions: + +1. Selective reverse sync scans top-level literal-JSON member spans and patches + only selected values plus required local separators. Unsupported or + ambiguous spans are rejected before writing. Preview metadata contains + operation names and separator changes, not values or diffs. +1. The baseline, source, and target writers re-observe no-follow staged + identity after a replace-boundary failure. The result distinguishes + `not_replaced`, `replaced`, and `indeterminate`; equal content alone never + proves a Luwu replacement. +1. Plan records share one closed validation path across create, decode, read, + and inspect. Resources are non-empty and contiguous, condition types are + closed, and numeric values reject booleans and out-of-range values. + +The exact public states, error projections, and compatibility promises belong +to [reference](../reference.md). + +## Historical implementation slices + +| Slice | Write set | Acceptance focus | +| ------------------------ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| A: literal-JSON patch | `src/luwu/reverse_sync.py`, selective-patch tests | Selected values change; unselected and undeclared bytes remain byte-for-byte stable | +| B: replace boundary | `src/luwu/baseline.py`, `src/luwu/mutations.py`, replace-boundary tests | Replace-before/after failures, staged identity, equal external content, and cleanup uncertainty | +| C: execution propagation | `src/luwu/reconcile.py`, execution tests | Three-state propagation, journal outcomes, recovery, and later `not-attempted` resources | +| D: record closure | `src/luwu/plan_record.py`, schema tests | Closed condition domain, non-empty records, contiguous ordinals, and consistent read paths | + +The main integration pass owned the ablation, owning-document updates, and +cross-slice verification. These historical write sets do not define permanent +agent or subagent scope. + +## Ablation and verification + +The guard-on/guard-off ablation reproduced a real counterexample for each +accepted guard. Production regressions then covered the complete writer +timelines, CLI and journal projections, read-only recovery, old fixtures, and +v1-v4 compatibility. The final closure recorded 274 passing unit tests plus +the M3 ablations, static checks, build checks, isolated CLI loop, and isolated +hook gate. + +The repair intentionally did not add a transaction engine, second ledger, +generic JSON editor, schema registry, automatic recovery, rollback, or a +strong-consistency promise against unrelated writers. diff --git a/docs/milestones/m3.md b/docs/milestones/m3.md index 696fcd7..b508dc1 100644 --- a/docs/milestones/m3.md +++ b/docs/milestones/m3.md @@ -1,110 +1,79 @@ -# M3:归属与可审计协调 - -本文件记录 M3 的交付边界、M3a 审查证据及 M3b/M3c 实现切片。自动重放、回滚和不受控外部写入者的强一致性不属于本里程碑契约。当前实现事实以 [status](../status.md) 为准,稳定接口由 [reference](../reference.md) 维护。 - -2026-09-13 的当前工作树复核发现原回归未覆盖的三个边界缺口;独立审查、消融、 -补齐分工与本轮验收记录见 [M3 follow-up](m3-followup.md)。下文保留原冻结范围及 -2026-09-12 的交付记录,不将历史通过状态当作本轮完成证据。 - -随后基于最新 `d9d7092` 的复核又发现失败结果和冲突处理的未覆盖场景; -本次计划、独立审查、消融与验收记录见 -[M3 失败结果与冲突边界补齐](m3-execution-closure.md)。 - -## 目标与分期 - -让 baseline、字段归属和冲突共同决定可审查的下一步。M3 完整范围沿用 [roadmap](../roadmap.md),本轮首先开发 M3a;不将只读观察等同于 M3 全部完成。 - -1. **M3a:只读三方观察。** 显式提供 public baseline,声明字段归属,对 desired / live / baseline 分类;输出字段决策元数据及未声明内容的变化信号。 -1. **M3b:显式接受与反向同步。** 定义 baseline 接受、字段到输入的明确映射、可审查补丁、确认与陈旧状态检查;只接受声明字段,写回后重新渲染和计算。不得将 live 文件复制进 Jinja 模板。 -1. **M3c:可恢复的多资源执行。** 在写入前定义持久计划的版本、输入绑定、部分成功、恢复及回滚边界;必须通过故障注入证明每个已提交目标均可追踪,再开放多资源 apply。 - -## M1/M2 收尾计划 - -- 重跑现有回归、隔离 CLI、构建、锁文件与全仓 hook gate;区分环境失败和实现失败。 -- 修复 Jinja 渲染孤立 surrogate 时,一个资源的编码异常中断 M2 全部观察的问题;添加真实多资源回归。 -- 核实 M1 文件 mode 与 fsync 顺序,并验证失败时保留旧目标。 -- 将新的证据写入 status 和 M1/M2 验收项,保留其原始功能范围。 - -## M3a 开发契约(审查与消融后冻结) - -- 新增 manifest / JSON schema version 3;version 1/2 行为保持各自兼容契约,v3 apply 明确拒绝。 -- v3 仅支持 JSON template 字段资源:`kind = "template"`、`comparison = "json"`、`owner = "fields"`、`scope = "fields"`、`content_sensitivity = "public"`。 -- `fields` 是非空顶层字面键到 `source`、`live`、`merge` 或 `ignore` 的映射;点号和斜杠均无路径含义。嵌套对象和数组作为整个字段比较,声明涵盖完整子树。`content_sensitivity = "public"` 覆盖 desired、live、baseline 输入;provider 不在本期接受范围。 -- `baseline` 是可选的根目录内输入路径,由用户在 manifest 中显式选择;Luwu 不自动生成或更新。它是用户提供的比较依据,不声称证明历史接受事件。无 baseline 时报告 `unbased`,不给出前向或反向候选。 -- baseline 使用严格 JSON 信封,准确字段集合为:`schema_version = 1`、`resource`、`source`、`target`、`owners` 和 `values`;版本必须为数值 1,拒绝布尔值(有限数字的等价拼写遵循 JSON 比较规则)。身份字符串和 owners 必须与当前声明完整、精确匹配(含 ignore);values 必须为对象,仅可包含声明且非 ignore 的字段。缺席表示该字段在 baseline 中不存在,不得回落到 desired 或解释为无 baseline。未知信封字段一律 blocked,错误不回显未知键和值。不得保存整个 live 文件或现有 Plan 对象。 -- baseline 路径不得与 manifest、任何 source/target(含 source 解析路径)相同或存在祖孙重叠;通过声明原路径调用 `open_parent_directory` / `read_regular_file_at`,不得先 resolve 后读取,拒绝叶节点与任一父目录 symlink。缺失、FIFO、目录、错误类型和无效内容均使该资源 blocked。允许其他资源继续观察。 -- 先严格解析 JSON,区分 missing 与 null、bool 与 number,保留数组顺序和数值精度。desired、live 均须为 JSON 对象,live 文件必须已存在;不猜测创建语义。 -- 对每个非 ignore 字段:D=L=B 为 unchanged,D=L≠B 为 converged;仅 D 变为 source_changed,仅 L 变为 live_changed;D/L 均变且不同为 conflict。 -- source_changed 仅在 owner 为 source/merge 时产生 forward_candidate;live_changed 仅在 owner 为 live/merge 时产生 reverse_candidate。相反方向和双方冲突均要求 review,不用 owner 覆盖冲突。候选不是可执行写入许可。 -- 未声明字段参与独立的 desired/live 比较,只输出 `undeclared_changed` 布尔值,不输出未知键名和值。baseline 不记录该区域,无法判断它的历史变化;字段冲突、unbased 和未声明变化信号可并存,不能被 ignore、formatting 或单一 in_sync 状态吞掉。 -- 输出不含任何配置值、原文、补丁或内容 hash。inspect/plan 不写文件、不启动外部能力;所有 v3 资源均不能 apply。 - -## 对抗性审查与消融 - -交由三个独立 agent 按授权/文件边界、归属/语义、可验证性/保密性审查。主 agent 汇总 blocking 项,记录采纳理由,再运行短小的行为探针:移除 baseline、owner、missing 区分或冲突判断时,应出现可见反例;移除通用路径、存储框架、合并引擎时,如果仍满足本切片的验收样例,则不引入这些抽象。 - -三组审查均要求补齐封闭信封、完整 owners 匹配、public 完整子树、对象根类型与 no-follow 原路径读取;均已采纳。归属审查另要求聚合状态不得掩盖 unbased/conflict/undeclared 信号,已纳入集成验收。保留 baseline 身份绑定,删除历史证明、时间戳及字段路径语法。 - -执行 `uv run experiments/m3_ablation.py`:参考设计 13 个场景通过;删除 baseline、ownership、missing 区分、冲突阻断分别出现 8、2、2、2 个反例;删除通用路径后 4 个顶层选择保持一致;删除未声明变化信号出现 1 个隐藏变化反例。本实验仅支持设计取舍,不替代生产实现测试。存储、补丁、写入恢复在本切片没有调用需求,留待 M3b/M3c 验证。 - -## M3a 历史开发分工 - -| 工作包 | 文件边界 | 接口与验证 | -| -------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| A:声明与路径校验 | `manifest.py`、`tests/test_manifest_m3.py` | `Resource` 增加 `fields` 只读映射、`baseline` / `baseline_name` 可选路径、`content_sensitivity`;v3 专属声明及跨资源 baseline 路径拒绝 | -| B:纯归属分类 | `ownership.py`、`semantic.py`、`tests/test_ownership.py` | `classify_fields(desired, live, *, fields, baseline, resource_name, source_name, target_name)`;只接受字节输入,返回 metadata-only fields / baseline_status / undeclared_changed,坏输入抛固定脱敏 `LuwuError` | -| C:观察与 CLI | `reconcile.py`、`cli.py`、`tests/test_m3.py` | v3 分派、安全读取 baseline、完整资源观察、版本 3 输出和 apply 拒绝;补正 M1 chmod/fsync 顺序 | -| 主 agent:收尾与汇总 | `rendering.py`、M1/M2 回归、文档、实验 | 修复 M2 编码异常,审查交界和失败路径,执行隔离 E2E、全套验证及最终文档对齐 | - -B 的每个字段结果包含 `name`、`owner`、`status`、`decision`、`reason`;decision 仅为 `none`、`forward_candidate`、`reverse_candidate`、`review`,无写入行为。baseline_status 为 `provided` 或 `absent`,结果提供 `to_dict()`。未实现接口不得作为已验证行为写入 status。 - -## 验收清单 - -- [x] M1/M2 实现缺口收尾及仓库 gate 证据对齐。 -- [x] 计划完成独立价值审查及快速消融,最终接口冻结后再并行开发。 -- [x] M3a 明确版本、字段归属、public 输入与 baseline 绑定。 -- [x] M3a 三方状态、归属冲突、未声明变化和严格 JSON 边界有测试。 -- [x] M3a CLI 元数据输出及零写入边界有集成测试。 -- [x] 主 agent 汇总代码 review、运行验证并同步 owning documents。 -- [x] M3b 首个单资源切片:显式 baseline acceptance、literal-JSON reverse-sync、preview/确认和写回后重算。 -- [x] M3b 完整字段输入映射与 mutation contract closure。 -- [x] M3c 多资源执行与只读恢复重观察契约。 - -## 当前进度评估与后续开发计划(2026-09-12) - -本轮以当前 checkout 的代码、测试和 owning documents 为准,结论如下: - -| 范围 | 当前结论 | 证据与阻断 | -| ---- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| M3a | implemented | v3 三方字段观察、严格 baseline、归属分类、未声明变化信号和只读 apply 边界已有生产代码与回归测试。 | -| M3b | implemented | v4 单资源 public `accept` 与 identity-mapped literal-JSON `reverse-sync` 已闭合;入口授权、字段选择、source/live/manifest/baseline stale recheck、父目录检查、提交后验证和 committed/unknown CLI 结果均有回归。 | -| M3c | implemented | version 5 manifest、full-preflight multi-resource execution、closed metadata journal、CAS 状态推进、真实 postcondition、stop/no-rollback、`record-inspect` 与只读 `recover`/`record-reobserve` 已闭合;自动重放和回滚明确排除在契约外。 | - -五个独立视角的 review 形成以下冻结决策:baseline、ownership、missing/null、conflict 和最小布尔型 `undeclared_changed` 均为不可消融的价值边界;通用字段路径、存储框架、merge engine 不属于当前观察切片。不能通过删除 M1/M2 的单资源或只读 guard 来开启多资源写入。多资源执行必须使用独立 capability,保持 v1–v4 的兼容和拒绝行为。 - -### M3b 收口 - -- 在 mutation 公共入口同时检查 manifest 资源总数、资源选择和 field 选择唯一性;多资源 v4 只可观察,不能借 `--resource` 变成部分授权的 mutation。 -- 给 baseline acceptance 和 reverse-sync 补齐 source/live/manifest/baseline 的陈旧检查、确认前零写入、写入后验证失败的 committed/unknown 语义,以及对应故障注入测试。 -- 继续禁止 undeclared 内容、动态 Jinja 整体回写、provider/secret 输入;稳定 `MutationResult` 只返回字段名、操作、路径、状态和脱敏错误,提交后验证失败不会伪装成未写入。 - -### M3c 最小可交付契约 - -1. 新增独立的多资源 execution manifest/capability 版本,v1–v4 行为不变。首个版本只开放显式 public、source-owned、whole-file 的可验证资源;不把 v4 字段 mutation 或 M2 comparison plan 隐式升级为可写。 -1. 生成 durable plan 前必须完成全量 preflight:声明资源与观察一一对应、稳定排序、路径/父目录无冲突、所有 source/target 身份和 manifest digest 仍匹配,任何 blocked/stale/conflict 都在首个 writer 前停止。 -1. journal 使用 closed、强类型、metadata-only schema,绑定 execution/mutation contract、manifest 身份、每个资源和 path 的 role/operation/相对路径/非内容身份与状态;不得保存 values、bytes、rendered、diff、patch、provider payload、secret 或 source/target 内容 hash;manifest digest 只用于绑定 manifest 身份。不要用关键词黑名单替代 schema 约束。 -1. 采用 `planned -> preflighted -> commit_intent -> committed` 的逐资源/逐路径记录。提交前先持久化 intent,原子替换后再持久化 committed;journal fsync、父目录 no-follow 和写入后的任何不确定性都只能产生 `unknown`/`recovery_required`,不得误报成功。 -1. 故障策略固定为 `on_failure = stop`、`rollback = never`:每个资源必须明确落入 unchanged、committed、unknown 或 not-attempted;部分成功不能掩盖任何一类状态。`recover`/record inspect 只重新观测并产生可继续处理的结果,不能自动重放旧输入、隐式补写或声称已回滚。 - -### 解耦开发包 - -| 包 | 不重叠写集 | 依赖与验收 | -| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| A:M3b contract closure | `src/luwu/mutations.py`、`src/luwu/baseline.py`、`src/luwu/reverse_sync.py`、`tests/test_m3b.py` | 依赖现有 v4 schema;覆盖单资源 guard、字段选择、stale、preview 零写入、committed/unknown 和 post-write replan。 | -| B:journal contract | `src/luwu/plan_record.py`、`tests/test_plan_record.py` | 与 A 的公开结果无代码耦合;覆盖 closed metadata schema、resource/path provenance、no-follow persistence、不可逆状态转移、fsync/崩溃和敏感值拒绝。 | -| E:execution manifest/capability | `src/luwu/manifest.py`、新增 `tests/test_manifest_m3c.py` | 与 A/B 独立;冻结新版本的 public/source/whole-file 多资源声明、兼容拒绝和路径关系,给 C 提供明确入口。 | -| C:多资源执行与恢复 | `src/luwu/reconcile.py` 的新 execution orchestration、必要的 `src/luwu/filesystem.py`、新增 `tests/test_m3c_execution.py` | 依赖 B 的 frozen record API 和 E 的 manifest capability;复用既有单文件 writer,不重写 reverse-sync;覆盖全量 preflight、稳定顺序、N 成功/N+1 失败、intent/commit 后崩溃、unknown 和零误写。 | -| D:CLI 与契约集成 | `src/luwu/cli.py`、`tests/test_cli.py` 及 CLI 专属新测试 | 依赖 A–C、E 的接口;接入新 capability 和只读 recover/record inspect,保持 v1–v4 的输出/错误码。 | -| 主 agent:集成与 owning docs | M1/M2/M3 回归、`docs/status.md`、`docs/reference.md`、本文件、隔离 E2E 与 gates | A/B/E 完成后冻结接口,C 完成后接 D;主 agent 统一合并交界、审查 metadata-only 输出、执行故障注入、更新实现状态;网络或缓存导致的外部 gate 阻断单独记录,不降级已验证的实现状态。 | - -开发顺序为 A/B/E 可并行,C 等 B/E 的状态和 capability 冻结后开始,D 可提前写只读契约测试但只能在 C 接口稳定后接线;主 agent 最后负责跨包集成和全套验证。M3c 在每个“已提交目标可追踪、未提交目标不被误写、未知状态不被重试”验收项通过前,不开放多资源 apply。 +# M3: Ownership and Auditable Reconciliation + +Status: closed within the repaired v3/v4/v5 contracts. + +This is the historical M3 delivery and closure record. The current public +manifest, CLI, JSON, error, and compatibility contract is owned by +[reference](../reference.md). The current implementation snapshot is owned by +[status](../status.md). This record preserves the M3 scope, review evidence, +and closure decisions as they stood during delivery. + +## Scope at closure + +M3 added responsibility and time to reconciliation: + +1. M3a added read-only three-way observation using an explicit public baseline + and declared field ownership. +1. M3b added explicit baseline acceptance and selective literal-JSON reverse + sync for one public resource. +1. M3c added explicit public whole-file multi-resource execution with a + metadata-only journal and read-only recovery observation. + +Automatic replay, rollback, dynamic-template reverse writes, provider or +secret inputs, and strong consistency against writers that ignore advisory +locks were outside the milestone. + +## Review-driven decisions + +The initial M3 review established that baseline identity, ownership, +missing-versus-null distinctions, conflict review, and undeclared-change +signals were necessary to make an observation auditable. It rejected a +generic field-path language, a storage framework, and a merge engine because +the accepted examples did not require them. + +The M3 follow-up found three additional boundary gaps: journal sidecar paths +could collide with declared resources, reverse-sync authorization could be +bound to a stale baseline, and recovery could report confirmation while a +fresh plan reported drift. The repair was implemented and recorded in +[m3-followup](m3-followup.md). + +The later execution closure found that journal publication could be confused +with target replacement, a standalone `not-attempted` resource could be +reported as confirmed, and an unselected field conflict could be bypassed by +reverse sync. The fixes and their evidence are preserved in +[m3-execution-closure](m3-execution-closure.md). + +The frozen-contract repair plan and its staged identity/value-domain decisions +are preserved in [m3-repair-plan](m3-repair-plan.md). Those records explain +why the implementation is narrow; they do not replace the current contract. + +## Historical development slices + +The work was divided by non-overlapping production and test write sets. The +table is a historical coordination record, not a permanent agent-scheduling +rule. + +| Slice | Historical write set | Acceptance focus | +| -------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| M3b contract closure | `src/luwu/mutations.py`, `src/luwu/baseline.py`, `src/luwu/reverse_sync.py`, M3b tests | Single-resource guard, selected fields, stale checks, zero-write preview, committed/unknown outcomes | +| Journal contract | `src/luwu/plan_record.py`, record tests | Closed metadata schema, path provenance, no-follow persistence, state transitions, sensitive-value rejection | +| Execution capability | `src/luwu/reconcile.py`, execution tests | Full preflight, stable ordering, partial success, unknown state, zero unintended writes | +| CLI and integration | `src/luwu/cli.py`, CLI tests, owning documents, experiments | Public output, read-only recovery, compatibility, failure and secrecy boundaries | + +Each slice was reviewed against the public contract before integration. The +main integration pass owned the cross-slice tests, experiments, documentation, +and final gates. + +## Closure audit + +| Area | Closure conclusion | +| ---------------- | --------------------------------------------------------------------------------------------------------------- | +| M3a observation | Implemented and covered by manifest, ownership, strict JSON, and read-only observation tests | +| M3b mutation | Implemented with explicit fields, stale checks, selective literal-JSON patching, and post-write verification | +| M3c execution | Implemented with full preflight, closed metadata journal, partial outcomes, read-only recovery, and no rollback | +| Boundary review | Symlink, path, journal, stale-input, replace-boundary, and recovery counterexamples were reproduced and covered | +| Scope discipline | Provider, secret, automatic recovery, rollback, and non-cooperating-writer guarantees remained outside M3 | + +The final M3 state is reported by [status](../status.md). Historical test +counts, commands, temporary directories, and gate results remain in the +follow-up, repair, and execution closure records linked above. diff --git a/docs/milestones/m4.md b/docs/milestones/m4.md index b93a87c..4cb75ed 100644 --- a/docs/milestones/m4.md +++ b/docs/milestones/m4.md @@ -1,257 +1,87 @@ -# M4:Provider、秘密与运营成熟度 - -状态:complete;方案经三份独立复核、快速消融和最终 gate 验证后关闭。 - -M3 在冻结的 v3/v4/v5 契约内已完成。M4 的目标是在不放宽 v1–v5 -边界的前提下,接入一个受控的 `rbw` 只读 provider,并证明秘密值的短暂 -生命周期、显式外部能力、元数据缓存、平台失败行为和发布门禁。产品方向由 -[roadmap](../roadmap.md) 维护;稳定的 manifest、CLI、JSON、错误和兼容契约 -在最终实现后归 [reference](../reference.md);开发与发布流程归 -`docs/maintenance.md`。 - -## 决策门 - -M4 只在以下条件都被当前代码、测试和 gate 证明后关闭: - -- v1–v5 的 manifest、JSON 结构、安全语义、只读/单资源 mutation、多资源 execution、 - journal、reobserve 和已有 M3 对抗回归保持兼容;M4 不通过修改 v5 偷渡 provider。 - human 输出可以增加安全元数据和控制字符转义,但不得改变写权限或秘密策略。 -- 新的 version 6 是独立的 provider execution capability。它只支持 - `template`、`owner = "source"`、`scope = "whole-file"`、 - `content_sensitivity = "secret"`,以及非空的显式 provider 引用。 -- v6 的 `capabilities` 是闭合集合,且本期必须精确为 `["subprocess"]`。manifest - 只声明需求,不构成本次运行授权;没有运行时 authority 时,load/plan/execute/recover - 都不能启动 provider。`network` capability 推迟到另一个有真实语义的 contract。 -- 每次 CLI 或直接库调用最多为每个声明 provider 获取一次。`plan` 是一次只读计算; - `apply --yes` 是一次新的、独立的计算,不绑定此前 preview:它在同一 authority 下 - 获取一次 provider 值,完成完整 preflight,随后只写这次 plan 固化的 bytes。写前 - preflight 不再次获取值;provider 轮换由下一次调用观察。recover 可以重新获取当前值, - 但只报告当前观察,不能证明历史秘密内容。 -- provider 失败、超时、畸形输出、可执行文件身份变化和 capability 缺失都 - fail closed,错误只含固定代码和边界,不含 stdout、stderr、provider item、 - field 或秘密值。 -- provider 返回的秘密只能在一次 render/preflight/write 调用链的进程内存中短暂存在。 - secret、原始 provider 输出、rendered bytes、diff、patch、content hash、secret-derived - size、provider reference、完整含 provider reference 的 manifest digest、baseline、 - journal、cache、backup、异常链和机器可读/人类输出均不得持久化或泄露。唯一允许的 - 持久化秘密出口是用户明确声明且位于 manifest root 外的 secret target;staging 必须 - 是同一受控目录内的 owner-only 临时项,正常和失败路径都要报告清理是否可确认。 -- v6 target 必须是绝对路径,且不能位于 manifest root、manifest、source、journal、 - cache 或 backup 的路径树内;父目录必须已存在、是受支持的安全目录边界,Luwu 不为 - secret target 自动创建父目录。target 缺失时以 `0600` 创建;已有 target 的 owner - 必须匹配当前用户、无 group/other 权限和特殊权限位,检查须在读取秘密前及写前重做。 - ACL、硬链接、符号链接、目录替换和无法确认的 owner/mode 一律阻断。该规则不能防止 - 有权修改目录的非合作 writer,威胁模型只承诺检测并 fail closed,不承诺消除 OS 级 TOCTOU。 -- v6 journal 使用独立的 closed secret-safe schema;可以复用 M3c 的状态转移和 CAS/写入 - 边界,但不复用 v5 的 manifest digest、内容尺寸或普通 path condition。v6 record 只保留 - contract、opaque execution id、资源 ordinal/公开资源标签、target 的非内容状态、 - committed/unknown/not-attempted 事实和事件;不保存 provider reference、secret-derived - metadata 或内容证据。历史提交无内容证明是契约限制,不由 recover 补偿。 -- cache 是显式 opt-in 的 metadata-only 诊断优化,保留它是为了完成 M4 的运营边界, - 不是值、归属、新鲜度、授权或恢复依据。它只记录固定的 provider type、能力、可执行 - 文件的非内容身份、状态和时间;不记录 resource name/path、item/field、value、payload、 - content hash 或可离线恢复秘密的等价物。只有显式 `cache-refresh` 写 cache, - `inspect/plan/apply/recover` 不写;过期、损坏、跨 executable identity 或不可读 cache - 不能升级为成功,inspect 也不隐式修复或删除。 -- 非 POSIX,或缺少 `O_NOFOLLOW`、目录 fd、目录 fsync、原子 replace、锁等原语的平台, - 在 library 和 CLI 两层明确返回 `platform_unsupported`。`platform-check` 只作诊断, - 不能成为后续执行的授权票据;replace 后 fsync/清理失败必须保留已改变/未知事实。 - -## 冻结的 version-6 形状 - -除 `version = 6` 外,根表只允许 `capabilities` 和 `resources`: - -```toml -version = 6 -capabilities = ["subprocess"] - -[resources.database] -kind = "template" -source = "templates/database.conf.j2" -target = "/home/user/.config/luwu-secret/database.conf" -owner = "source" -scope = "whole-file" -content_sensitivity = "secret" - -[resources.database.providers.db_password] -type = "rbw" -item = "database-prod" -field = "password" -``` - -模板只能通过受限的 `secrets.` namespace 使用 provider 值;公共 `variables` 仍须 -经现有 public loader 边界认证,且不能含 `secrets` 或敏感键。provider 表和 capability -表闭合:alias 是 ASCII 标识符(`[A-Za-z][A-Za-z0-9_]{0,63}`,禁止 namespace 保留 -名),`type` 只允许 `rbw`,item/field 是非空、最多 256 个 UTF-8 bytes、无控制字符、 -NUL 或前导 `-` 的 opaque argv 值。它们可以是 rbw 支持的 name/URI/UUID,但本期不声称 -跨账户或 vault 的不可变身份;执行上下文由显式 absolute executable、当前 uid 和受信 -目录身份绑定,重名/缺失/空字段由 rbw 结果固定失败,不做 fallback。 - -v6 不允许 `comparison`、`fields`、`baseline`、`reverse_sync`、`variables` 或 -version 1–5 的隐式 kind;v1–v5 继续拒绝 `providers`、`capabilities`、secret -content sensitivity 和 v6 target 形状。 - -## 运行时 provider 与授权契约 - -公共 seam 固定为以下语义(具体类名可以按实现需要保持最小): - -```python -build_plan( - manifest, - *, - authority: ProviderAuthority | None = None, - resolver: ProviderResolver | None = None, -) -> Plan -execute_execution_plan( - plan, - record_path, - *, - confirm: bool, - authority: ProviderAuthority | None = None, - resolver: ProviderResolver | None = None, -) -> ExecutionResult -reobserve_execution_record( - record_path, - *, - authority: ProviderAuthority | None = None, - resolver: ProviderResolver | None = None, -) -> dict[str, object] -``` - -`load_manifest` 永远只解析。v6 没有 authority 时可以返回 metadata-only -`capability_required` blocked observation,也可以由显式直接库调用抛出固定错误,但 fake -resolver 必须证明 provider 启动次数为零;CLI 的 `--allow-subprocess` 与必需的 -`--rbw-executable ABSOLUTE_PATH` 只负责构造 authority,不能由 manifest 自授权。 - -rbw adapter 使用 argv `[executable, "get", "--field", field, item]`、`shell=False`、 -`stdin=DEVNULL`、最小环境和固定 cwd,不调用 sync/login/unlock,不建立 Luwu 自身网络连接。 -stdout/stderr 必须在读取过程中受上限约束;超时杀死整个 process group 并确认 pipes/子进程 -终止;输出必须是严格 UTF-8、无 NUL,按契约去掉最多一个末尾 LF/CRLF,保留内部换行, -空值是 provider error 而不是 fallback。执行前检查 executable 是当前用户拥有、regular、 -祖先目录不可被 group/other 写的 absolute path,并在 spawn 后复核 device/inode/mode/size/ -mtime 身份;身份变化停止本次调用并报告固定错误。该检查对“检查后到 exec 前”的竞争只 -提供检测性保障,不伪称为强隔离。 - -## 开发切片 - -1. **M4a:schema、authority、provider seam 和 platform core。** A 拥有 - `manifest.py`、`providers.py`、`errors.py`、`platform_support.py` 及对应的 - manifest/provider/platform 单元测试。交付 v6 closed schema、authority 类型、固定 - provider 错误、fake-rbw 注入 seam、argv/timeout/UTF-8/NUL/size/identity 行为,以及 - v1–v5 compatibility。平台矩阵先固定为 Linux x86_64、Python 3.12–3.14、rbw 1.15.x; - 其他 POSIX 先显示 unsupported,不能因常量存在而声称支持。 -1. **M4b:secret object 和 render seam。** B 拥有 `secrets.py`、`rendering.py` 及 - secret 测试,冻结 `render_template(..., secrets=SecretRenderContext | None)`。 - secret context 只被 renderer 私有 token 解封;业务对象的 repr/JSON/dataclass/pickle/ - exception 都不能得到 secret 或 rendered bytes;alias collision、缺失 alias、错误 - sentinel、public fallback 和短生命周期边界都要覆盖。B 不修改 reconcile。 -1. **M4c:v6 observation/execution/recovery。** C 拥有 `reconcile.py`、v6 专用 - `plan_record.py` 记录类型及 execution 测试。C 依赖 A/B,按一次获取语义接线,复用 - M3c writer 的逐资源状态、staged identity、CAS、committed/unknown/not-attempted 和 - reobserve-only 边界;v6 target 权限检查、full preflight-before-journal、秘密 target - 与 v5/v4 mutation 拒绝必须接入。v6 recover 无 authority 时仍能读取 journal 事实, - 有 authority 时只补充当前 provider observation,不 replay/rollback。 -1. **M4d:最小 metadata cache。** D 只拥有 `provider_cache.py` 及 cache 单元测试。 - cache 写入私有化为 owner-only atomic 0600,支持 `cache-inspect`/显式 `cache-refresh` - 所需的最小 API;不实现 provider registry、跨范围 key、secret hash、transaction - engine 或执行决策接缝。过期/损坏/身份不匹配只产生诊断状态。 -1. **M4e:CLI、release 和维护流程。** E 在 C/D 接口稳定后拥有 `cli.py`、M4 CLI 测试、 - `docs/maintenance.md` 和 `.github/workflows/ci.yml`。接入 `--allow-subprocess`、 - `--rbw-executable`、recover capability flags、cache 命令和 `platform-check`;human/ - JSON 使用安全 metadata projection,修复 control-character 注入和 M3 ownership/ - impact 信息缺失。E 不把 platform-check 结果当授权。 - -## 独立审查与消融 - -初稿已由不同 agent 分别审查,复核意见已纳入上面的冻结契约: - -- `gpt-5.6-sol`、medium:调用链、版本兼容、状态机、TOCTOU 和 gate 的逻辑 - 推理; -- 价值取向 agent:归属可见性、秘密最小暴露、显式能力、失败诚实性与恢复 - 边界的对抗性场景; -- 独立工程 agent:切片依赖、公共 API 兼容和可测试性。 - -主 agent 汇总后运行快速消融。必须使用真实生产调用链或真实 adapter seam、隔离目录和 -fake-rbw,不读取真实 vault。保留能让真实反例失败的边界:运行时 authority(无授权零 -启动)、provider output 的固定错误边界、secret render context、v6 record privacy -guard(无 digest/size/reference)、owner-only target、closed metadata schema、 -stale/unknown/not-attempted、cache 不参与决策、每次 filesystem 操作自身检查和平台 -fail closed。 - -如果删掉通用 provider registry/plugin discovery、lazy provider、`network` capability、 -通用 transaction engine、secret hash/value fingerprint、自动 replay/rollback、第二套 -ledger、platform-check 授权缓存或 cache 中的 per-item 状态后参考场景仍通过,则不得引入。 -metadata cache 本体暂保留,只因 M4 roadmap 明确包含运营诊断持久化;消融必须证明它被 -删除时诊断能力下降,但 plan/execute/recover 安全判断完全不改变。 - -## 解耦开发包与验收 - -| 包 | 不重叠写集 | 依赖与验收 | -| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -| A:schema/provider/platform contract | `src/luwu/manifest.py`、`src/luwu/providers.py`、`src/luwu/errors.py`、`src/luwu/platform_support.py`、`tests/test_manifest_m4.py`、`tests/test_providers.py`、`tests/test_platform.py` | v6 closed schema、runtime authority、fake-rbw argv/timeout/error/identity、platform probe、v1–v5 compatibility | -| B:secret render boundary | `src/luwu/secrets.py`、`src/luwu/rendering.py`、`tests/test_m4_secrets.py` | renderer-private secret context、无 repr/序列化、secret 不进 RenderError/RenderedTemplate repr、public vars 不回退 | -| C:v6 execution integration | `src/luwu/reconcile.py`、`src/luwu/plan_record.py`、`tests/test_m4_execution.py`、`tests/test_plan_record_m4.py` | v6 plan/execute/preflight、一次 lookup、0600、M3c unknown/recovery/reobserve、独立 journal 无 secret | -| D:cache | `src/luwu/provider_cache.py`、`tests/test_provider_cache.py` | closed metadata schema、atomic 0600 write、TTL/corrupt/identity、值和 reference 不落盘,且不参与决策 | -| E:CLI/release/maintenance | `src/luwu/cli.py`、`tests/test_m4_cli.py`、`docs/maintenance.md`、`.github/workflows/ci.yml` | explicit flags、metadata-only human/JSON、cache commands、platform-check、clean-install/build matrix | -| 主 agent:集成 | `docs/reference.md`、`docs/design.md`、`docs/status.md`、`docs/roadmap.md`、本文件、cross-slice tests/experiments | 合并边界、运行全部 M1–M4 tests/ablations/static/build/hooks,确认 secret sentinel 全出口无泄露 | - -A:schema + authority + provider + platform core -├─ B:secret/render seam -├─ D:metadata cache -└─ C:v6 plan/refresh/execute/recover(依赖 A+B) -└─ E:CLI + cache commands + CI/release(依赖 C+D) -└─ 主集成:文档、cross-slice tests、消融和全量 gate - -每个开发 agent 只在自己的 fork/workspace 编辑其写集,不提交或推送;主 agent 负责按 -上述顺序审查和整合,不把同一个测试 helper 或公共入口分给多个 agent。 - -## 最终 gate - -必须使用临时目录和 fake-rbw,不读取真实 vault: - -- 全量 unittest、M1–M3 四份消融和 M4 消融/secret sentinel experiment; -- Ruff check/format、`ty`(若当前环境可用)、compileall、`uv lock --check`、wheel/sdist - build、`git diff --check`; -- 隔离副本的完整 `prek run --all-files`;当前 checkout 的共享 `.agents` 只读 - 错误单独标为环境阻断; -- v1–v5 compatibility、v6 capability denied/allowed、provider lookup-count、timeout/ - non-zero/malformed/oversize/executable race、secret success/error/JSON/human/journal/ - cache/staging residue 扫描;secret target 是允许的唯一内容命中; -- v6 record-inspect 无 provider 仍显示 journal 事实,recover 无 authority 不运行 provider, - authority 下只报告 current convergence;provider 轮换、unknown 当前相等、外部 writer - 和 replace 后不确定均保持诚实状态; -- `platform-check`、library fail-closed、目标 filesystem fsync/cleanup failure 分类; -- clean install gate:从 wheel 和 sdist 分别安装到全新 venv,运行 `luwu --version`、 - v1–v6 smoke,确认无源码目录依赖;CI 至少执行声明的 Linux/Python 矩阵和 unsupported - platform 分支测试。 - -只有上述证据齐全后,才把本文件状态改为 complete,并在 `docs/status.md` -中写入当前 checkout 的实际 HEAD、命令、退出码、测试数和 blocked/unrun 项。 - -## 关闭记录(2026-09-16) - -当前 checkout 的 HEAD 为 -`2307f32945c8cbf64adac54526425a314a061232`。fetch 后远端 `origin/master` -已经是该 HEAD,因此不需要 rebase 或 fast-forward。实现、文档和测试改动 -保持未提交、未推送。 - -最终 gate 结果: - -- 343 项 unittest 通过; -- 四份 M3 消融、M4 方案消融和 secret sentinel experiment 通过; -- Ruff check/format、`ty check src tests`、compileall、`uv lock --check` - 和 `git diff --check` 通过; -- `/tmp/luwu-m4-prek-final2.NR0USH` 隔离副本的完整 `prek run --all-files` - 及 hook 后 byte check 通过; -- wheel 与 sdist 构建通过;全新 venv 的 wheel 安装和完整 343 项测试在 - Python 3.12.9、3.13.15、3.14.7 通过,sdist 安装和完整 343 项测试在 - Python 3.12.9、3.14.7 通过,导入路径均为 `site-packages`; -- `platform-check --json` 返回支持的 Linux/x86_64、Python 3.14.7; - unsupported-platform 分支由 `tests/test_platform.py` 覆盖; -- `/tmp/luwu-m4-package-final3-escalated.7q3PQS` 保存本轮 package gate 产物和临时 - venv。真实 vault/provider 未使用,provider 均为 fake-rbw。 - -未运行的是远程 GitHub Actions 本身;`.github/workflows/ci.yml` 已声明 -Linux/Python 3.12-3.14 矩阵和 wheel/sdist clean-install gate,本地用同一 -三个 Python 版本执行了对应测试。首次 sandbox 网络失败后,构建、ty、 -hook 依赖和 Python 3.13 安装均通过授权重试完成。 +# M4: Providers, Secrets, and Operational Maturity + +Status: complete within the frozen version-6 provider, secret, persistence, +platform, and release contracts. + +This is the M4 historical scope and closure record. The current versioned +manifest, CLI, JSON, error, provider, secret, journal, cache, and platform +contract is owned by [reference](../reference.md). The current implementation +snapshot is owned by [status](../status.md). This record keeps the M4 +decision gates, review evidence, write-set boundaries, and final gate result. + +## Scope and decision gates + +M4 added one controlled `rbw` provider path without changing the v1-v5 +boundaries. The accepted capability was intentionally narrow: + +- version 6 is independent from v1-v5 and requires explicit runtime + subprocess authority; +- provider lookup, executable identity, output bounds, secret rendering, + secret-target permissions, and unsupported platform behavior fail closed; +- provider values and rendered secret content stay in process memory except + for the explicitly declared external secret target; +- v6 records and the opt-in cache are metadata-only and cannot authorize + reconciliation; +- recovery is observation only and does not replay or roll back historical + secrets; +- the platform and release matrix is claimed only where the required + filesystem primitives and package gates were verified. + +The exact manifest shape, capability flags, provider errors, secret redaction, +record schema, cache fields, and public output are maintained in +[reference](../reference.md). They are not duplicated in this milestone +record. + +## Historical delivery slices + +M4 used independent implementation slices with explicit write sets: + +| Slice | Historical write set | Acceptance focus | +| ----------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| M4a: schema and provider seam | `manifest.py`, `providers.py`, `errors.py`, `platform_support.py`, related tests | Closed version-6 schema, runtime authority, bounded adapter, executable identity, platform probe | +| M4b: secret render boundary | `secrets.py`, `rendering.py`, secret tests | Private render context, no repr/serialization leakage, no public fallback, short lifetime | +| M4c: execution integration | `reconcile.py`, `plan_record.py`, execution tests | One lookup per calculation, full preflight, owner-only target, unknown/recovery semantics | +| M4d: metadata cache | `provider_cache.py`, cache tests | Closed metadata schema, atomic owner-only write, TTL/corruption/identity diagnostics | +| M4e: CLI and release workflow | `cli.py`, CLI tests, maintenance, CI workflow | Explicit authority flags, safe projections, cache commands, platform diagnostics, clean installs | +| Main integration | Owning documents, cross-slice tests, experiments, final gates | Contract alignment, secret sentinel coverage, package and hook verification | + +These write sets describe one completed delivery. They are not permanent +subagent or agent-scheduling rules. + +## Independent review and ablation + +The M4 proposal was reviewed from logic, ownership, confidentiality, +capability, filesystem-boundary, consent, and verifiability perspectives. +The final design kept only boundaries with a production call path or a +reproducible counterexample. Ablation removed provider registries, lazy +providers, network capability, generic transaction engines, secret +fingerprints, automatic replay/rollback, and cache decision hooks. + +The remaining metadata cache was retained only because the roadmap explicitly +included operational diagnostics. It was verified not to participate in plan, +execute, or recover decisions. All provider tests used a fake executable or +injected resolver and did not access a real vault. + +## Closure evidence + +The final M4 gate on 2026-09-16 recorded: + +- 343 unit tests passed; +- M3 and M4 ablations plus the secret-sentinel experiment passed; +- Ruff, `ty`, compileall, lock, diff, wheel, and sdist checks passed; +- the isolated full hook run and post-hook byte check passed; +- fresh wheel installs passed the full suite on Python 3.12.9, 3.13.15, + and 3.14.7; fresh sdist installs passed on Python 3.12.9 and 3.14.7; +- the verified platform was Linux x86_64 with Python 3.14.7, while the + unsupported-platform branch was covered by tests; +- remote GitHub Actions itself was not dispatched. + +The original record contained temporary gate paths and environment notes; they +remain historical evidence here and are intentionally not copied into +[status](../status.md). + +## Limits retained + +M4 did not add network providers, automatic replay or rollback, historical +secret-content proof, or strong consistency against non-cooperating writers. +Those limits remain explicit in the current contract and status snapshot. diff --git a/docs/product.md b/docs/product.md index bb4d237..649b7db 100644 --- a/docs/product.md +++ b/docs/product.md @@ -99,4 +99,11 @@ This document owns what Luwu is trying to become and why it is valuable. Current ## Current starting point -The seed implementation starts with Python and uv, explicit `.j2` templates, and semantic drift. Controlled reverse sync and an rbw provider are product exploration directions and future hypotheses, not current capabilities. This reflects the current preference for fast iteration and a manageable, reviewable dependency supply chain; language choice is not treated as an intrinsic security guarantee, and cross-platform support remains a validation target rather than a completed matrix. These are starting assumptions for exploration, not the product's final form. +The initial seed implementation started with Python and uv, explicit `.j2` +templates, and semantic drift. Controlled reverse sync and an rbw provider +began as product exploration directions; the current accepted implementation +scope is maintained in [status.md](status.md), not in this historical starting +point. This reflects the preference for fast iteration and a manageable, +reviewable dependency supply chain. Language choice is not treated as an +intrinsic security guarantee, and cross-platform support remains a validation +target rather than a completed product-wide matrix. diff --git a/docs/roadmap.md b/docs/roadmap.md index 32d613c..0a8858e 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,35 +1,54 @@ # Luwu Delivery Roadmap -Status: directional roadmap +Status: directional roadmap; M1-M4 are closed within their recorded scopes. -This document turns the current product seed into a small number of delivery milestones. It defines sequence and boundaries, not detailed contracts or current implementation status. The product direction remains in [product.md](product.md); verified implementation facts remain in [status.md](status.md); each completed milestone keeps its own closure record under [milestones/](milestones/). +This document turns the product seed into a small number of delivery +milestones. It defines sequence and boundaries, not detailed contracts or the +current implementation snapshot. Product direction remains in +[product.md](product.md); verified implementation facts remain in +[status.md](status.md); each completed milestone keeps its own closure record +under [milestones/](milestones/). The roadmap is allowed to change when evidence changes the product direction. A change to an active milestone's scope should be explicit; a closed milestone is not rewritten to absorb new work. ## Milestone map -| Milestone | Focus | Completion outcome | -| --------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| M1 | Developer confidence preview | A safe, forward-only single-resource loop is observable, explainable, and explicitly applicable. | -| M2 | Resource and semantic drift foundation | Multiple declared resources and explicitly supported resource/format experiments can be compared without claiming equivalence beyond their evidence. | -| M3 | Ownership and auditable reconciliation | Baselines, field ownership, conflicts, controlled reverse sync, and recoverable multi-resource plans have explicit contracts. | -| M4 | Providers, secrets, and operational maturity | External providers, secret boundaries, persistence, portability, and release-quality operational behavior are verified without hidden capabilities. | +| Milestone | Focus | Completion outcome | +| --------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| M1 | Developer confidence preview | Closed: a safe, forward-only single-resource loop is observable, explainable, and explicitly applicable. | +| M2 | Resource and semantic drift foundation | Closed: declared resources and supported format experiments are compared without claiming unsupported equivalence. | +| M3 | Ownership and auditable reconciliation | Closed: baselines, ownership, conflicts, controlled reverse sync, and recoverable plans have explicit contracts. | +| M4 | Providers, secrets, and operational maturity | Closed: external providers, secret boundaries, persistence, portability, and release behavior are verified without hidden capabilities. | ## M1: Developer confidence preview -M1 is the current closed functional slice. Its fixed scope and exit evidence are recorded in [milestones/m1.md](milestones/m1.md). It intentionally does not imply multi-resource orchestration, reverse sync, baselines, providers, or secret persistence. +M1 was the initial closed functional slice. Its fixed scope and exit evidence +are recorded in [milestones/m1.md](milestones/m1.md). It intentionally did not +imply multi-resource orchestration, reverse sync, baselines, providers, or +secret persistence. ## M2: Resource and semantic drift foundation -M2 expands the resource model only after the single-resource boundary has proven useful. It establishes the contracts and tests for multiple resources, an observed literal-copy kind beyond the M1 slice, semantic observation of a supported format, and safe handling of partial or blocked plans. M2 comparison experiments are read-only until ownership and write semantics are accepted in M3. The exact supported formats and behavior belong in the M2 reference/design documents, not in this roadmap. +M2 expanded the resource model after the single-resource boundary had proven +useful. It established multiple-resource observation, an observed literal-copy +kind, semantic observation of a supported format, and safe handling of partial +or blocked plans. M2 comparison experiments were read-only until ownership and +write semantics were accepted in M3. The exact behavior belongs in +[reference](reference.md), not in this roadmap. ## M3: Ownership and auditable reconciliation -M3 adds time and responsibility to reconciliation: accepted baselines, declared field ownership, conflict classification, selective reverse sync, and durable or recoverable plans. Multi-resource apply and rollback semantics belong here only with an explicit partial-success and recovery contract. +M3 added time and responsibility to reconciliation: accepted baselines, +declared field ownership, conflict classification, selective reverse sync, and +durable or recoverable plans. Multi-resource apply and rollback semantics were +separated by explicit partial-success and recovery boundaries. ## M4: Providers, secrets, and operational maturity -M4 adds narrow external providers such as rbw, secret-aware inputs, persistence and cache boundaries, explicit subprocess/network capabilities, and the platform/release matrix. Provider-managed secrets must remain outside repositories, diffs, logs, caches, backups, and machine-readable output. +M4 added a narrow rbw provider, secret-aware inputs, persistence and cache +boundaries, explicit subprocess authority, and the platform/release matrix. +The current v6 contract remains narrow; it does not imply network providers or +automatic recovery. ## Roadmap completion rule diff --git a/docs/status.md b/docs/status.md index 505e5c2..85c3209 100644 --- a/docs/status.md +++ b/docs/status.md @@ -1,276 +1,45 @@ # Luwu Implementation Status -Status: M4 complete within the frozen public v1-v6 contracts; automatic replay, -rollback, and strong consistency against unrelated writers remain outside scope. - -This document records what the repository actually implements. The fixed M1 scope and closure checklist are maintained in [milestones/m1.md](milestones/m1.md); the M2 observation scope and closure checklist are maintained in [milestones/m2.md](milestones/m2.md); the M3a implementation boundary and closure evidence are maintained in [milestones/m3.md](milestones/m3.md); the M4 closure record is maintained in [milestones/m4.md](milestones/m4.md). This document does not expand the product scope in [product.md](product.md), and it does not replace the contracts in [reference.md](reference.md). - -The earlier M3 execution/conflict closure below is historical evidence for -then-current revisions. The current checkout completed the frozen-contract -repair recorded in [milestones/m3-repair-plan.md](milestones/m3-repair-plan.md); -the current closure evidence is recorded below. - -## Current implementation - -M1 provides a complete, isolated loop for explicitly declared local template and symbolic resources: - -```text -manifest -> inspect/plan -> explicit apply -> post-apply verification -``` - -The current implementation also requires plans to be issued by the manifest -loader and planner, compares template output byte-for-byte unless a future -format adapter supplies evidence, records source/target identities, serializes -cooperating writers with a directory lock, and distinguishes `no_changes`, -`committed`, `committed_but_verification_failed`, `committed_state_unknown`, -and `verification_failed`. M1 template variables require an explicit -`variables_sensitivity = "public"` declaration and are loader-classified -manifest literals; provider and secret inputs remain outside the accepted data -path. - -The following capabilities remain outside M1: - -- provider or rbw integration; -- secret-aware inputs or secret persistence; -- baselines and durable plan records; -- field ownership and controlled reverse sync; -- merge resources, additional link kinds, structured YAML comparison, and general formatter support; -- multi-file transactional rollback and a broad platform matrix. -- protection against unrelated processes that ignore Luwu's advisory directory - lock; M1 does not claim those races are safe, and a kernel-level - compare-and-swap primitive is future work. - -M2 now implements version 2 read-only observation: multiple resources are -validated and planned in stable order, cross-resource path conflicts are -rejected, literal `copy` resources are observed as exact bytes, and template -resources may opt into a strict JSON comparison. JSON -formatting equivalence is `formatting/noop`; parsed semantic drift is -`drifted/report`; unsupported input is `blocked/block`. Version 2 `apply` is -rejected with `m2_read_only` before any write. M2 does not implement -multi-resource apply, rollback, baselines, field ownership, or reverse sync. - -M3a now implements version 3 read-only field observation: explicit public JSON -template resources declare literal top-level field owners, may name an -explicit baseline envelope, and produce metadata-only three-way field -classification with strict JSON type distinctions. Baselines are read through the declared path with no-follow -descriptor operations and are never created or updated. Missing baselines are -reported as `unbased`; one-sided changes produce ownership-aware candidates, -two-sided changes require review, and undeclared desired/live changes produce a -separate boolean signal. Version 3 apply is rejected with `m3_read_only` before -any writer path. M3a itself does not implement acceptance or reverse sync; -persistent plans and multi-resource execution are provided by the separate M3c -contract; rollback remains explicitly outside the frozen scope. - -M3b now adds version 4 as a narrow public mutation slice. `accept` can -explicitly write selected desired/live fields to a declared baseline, and -`reverse-sync` can write selected live-owned fields through an explicit -literal-JSON source mapping. Both commands require one resource, explicit -fields, and `--yes`; previews are zero-write and results are metadata-only. -Dynamic Jinja reverse writes, undeclared content, provider/secret inputs, and -version 4 `apply` remain blocked. The module-level single-resource guard, -identity-only mapping, stale/parent checks, post-write verification, and -structured committed/unknown CLI outcomes close the frozen M3b contract. - -M3c now has a narrow version 5 execution capability for explicit public, -source-owned, whole-file template and symbolic resources. Planning uses stable -resource order and full preflight; confirmed execution writes a closed, -metadata-only `PlanRecord` before and after each intent/commit boundary, stops -without rollback, and records committed, unchanged, unknown, and -not-attempted resources. The CLI requires an explicit journal path for -confirmed version 5 apply and exposes `record-inspect` plus the read-only -`recover`/`record-reobserve` commands, all restricted to the version-5 -execution contract. Automatic replay, rollback, and guarantees against -unrelated writers that ignore advisory locks remain explicitly outside scope; -the implemented M3c contract is complete without those behaviors. - -M4 now implements an independent version 6 provider execution capability. -Version 6 has a closed manifest shape, explicit runtime subprocess authority, -one bounded `rbw get --field FIELD ITEM` lookup per provider per calculation, -fixed provider error boundaries, executable identity checks, and platform -fail-closed behavior. Secret values enter only the private renderer context and -the in-process write path; the v6 journal, cache, diagnostics, errors, and -machine-readable projections exclude secret values, provider references, -rendered content, content hashes, and secret-derived metadata. Secret targets -are external owner-only 0600 files with no automatic parent creation. - -M4 also provides a separate closed `SecretPlanRecord`, read-only current -re-observation, explicit metadata-only provider cache inspection/refresh, and -the `platform-check` diagnostic. Existing v1-v5 paths remain provider-free -and retain their prior read-only, single-resource mutation, and multi-resource -execution boundaries. The CI workflow declares the Linux x86_64 Python -3.12-3.14 matrix and clean wheel/sdist package checks; automatic replay, -rollback, network providers, and strong protection from non-cooperating -writers are not implemented. - -## 2026-09-16 M4 closure - -After fetching `origin`, it already pointed at the current HEAD -`2307f32945c8cbf64adac54526425a314a061232`; no rebase or fast-forward was -needed. The implementation and documentation changes remain uncommitted and -unpushed in this worktree. - -The final local evidence is: - -```text -343 unittest tests: passed -M3 ablation, follow-up ablation, execution-closure ablation, final-closure ablation: passed -M4 plan ablation and secret sentinel experiment: passed -ruff check/format, ty check src tests, compileall, uv lock --check, git diff --check: passed -isolated prek run --all-files and post-hook byte check: passed -platform-check --json: supported Linux/x86_64, Python 3.14.7 -wheel and sdist build: passed -fresh wheel install and full 343-test suite: passed on Python 3.12.9, 3.13.15, and 3.14.7 -fresh sdist install and full 343-test suite: passed on Python 3.12.9 and 3.14.7 -``` - -The isolated hook copy was -`/tmp/luwu-m4-prek-final2.NR0USH`; the final package gate and venvs were -`/tmp/luwu-m4-package-final3-escalated.7q3PQS`. The hook and package directories are -temporary and outside the checkout. Network-dependent dependency setup -required authorized retries after sandbox DNS failures. The remote GitHub -Actions workflow was not dispatched from this session; its declared -3.12-3.14 Linux matrix and unsupported-platform unit tests are present in -`.github/workflows/ci.yml` and were locally exercised with the same three -Python versions. - -## 2026-09-14 frozen-contract repair closure - -The current checkout started from `83ca72e` after a direct remote `master` ref -check returned the same commit. The M3 repair closes the three independently -reviewed gaps: literal-JSON reverse-sync now patches only selected value spans -and required local separators; baseline, M3b source, and M3c target writers -classify the replace boundary from staged no-follow identity; and v5 -`PlanRecord` conditions use a closed value domain with non-empty contiguous -resources. Equal bytes from an independent target are not treated as a known -Luwu commit. - -The repair adds 31 focused regression tests, bringing the full suite to 274 -passing tests. The final verification was run against the current worktree -before submission: - -```text -PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -B -m unittest discover -s tests -v # 274 passed -uv run experiments/m3_ablation.py -uv run experiments/m3_followup_ablation.py -uv run experiments/m3_execution_closure_ablation.py -uv run experiments/m3_final_closure_ablation.py -ruff check src tests experiments -ruff format --check src tests experiments -UV_TOOL_DIR=/tmp/luwu-uv-tools-m3-final uvx ty check src tests -PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -B -m compileall -q src tests -UV_CACHE_DIR=/tmp/luwu-uv-cache-m3-final uv lock --check -UV_CACHE_DIR=/tmp/luwu-uv-cache-m3-final uv build --out-dir /tmp/luwu-m3-dist.fHihxw # wheel + sdist -git diff --check -temporary M1 CLI: plan -> apply --yes -> inspect; content/mode/symlink/temp-entry checks passed -isolated prek: all hooks passed; exact tracked and unignored-file byte check passed -``` - -The isolated hook copy was `/tmp/luwu-m3-gate-submit.7jHFAv`; it contained every -tracked and unignored current file and passed the full fixed hook set, including -`ty` and `mdformat`. Build artifacts are in `/tmp/luwu-m3-dist.fHihxw/`. -Network-dependent dependency setup required an authorized external retry; no -user configuration or repository fixture target was modified by verification. - -M3a, M3b, and M3c are complete within the repaired frozen contracts. This does -not add exact reviewed-plan consent, automatic replay/rollback, or strong -consistency against unrelated writers. M4 is closed within the version-6 -provider, secret, portability, and operational contract described above. - -## Verification of the 2026-09-13 follow-up - -The earlier follow-up recorded these results on the POSIX development environment. They are historical evidence; the subsequent closure review is recorded below. - -```text -PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -B -m unittest discover -s tests -v # 213 tests passed -PYTHONPYCACHEPREFIX=/tmp/luwu-compile python3 -m compileall -q src tests -UV_CACHE_DIR=/tmp/luwu-uv-cache uv lock --check -ruff check src tests -ruff format --check src tests -git diff --check -M3a regression: tests/test_manifest_m3.py, tests/test_ownership.py, and tests/test_m3.py -M3b regression: tests/test_m3b.py and the v4 manifest/mutation boundary tests -M3c record regression: tests/test_plan_record.py and tests/test_m3c_execution.py -M3c CLI regression: tests/test_cli.py -isolated CLI fixture E2E: plan -> apply --yes -> inspect; clean post-apply state -``` - -The manual isolated CLI E2E check used a temporary copy of `tests/fixtures/m1`, confirmed the generated file content and mode `0644`, confirmed it was not a symlink, and confirmed no temporary `.luwu-*` entry remained. No repository fixture target was mutated. The fixture is a manual E2E input, not a hidden test dependency. - -The M2 regression suite additionally uses temporary projects to verify stable -multi-resource observation, cross-resource path rejection, literal-copy -observation, strict JSON formatting/drift/unsupported boundaries, resource- -level error collection, metadata-only output, and the zero-write version 2 -apply boundary. It confirms that a changed in-memory manifest version cannot -turn an M2 plan into a write-capable plan. - -The 213-test suite, compileall, Ruff check/format, lockfile validation, and -`git diff --check` pass. Both M3 ablation experiments pass. The earlier -cache/network limitations are historical: this follow-up successfully built -the wheel and source distribution and ran the repository hooks with -`PREK_HOME=/tmp/luwu-prek`. Explicit `--files` hook runs include all new, -untracked follow-up files; `-a` alone checks only tracked files. The full -tracked-file gate cannot open the protected `.agents/skills` files for writing -in this sandbox. Final complete-hook verification therefore uses an isolated -temporary copy of every tracked and untracked repository file, leaving the -original index and protected files untouched. - -## 2026-09-13 follow-up - -The current-worktree audit reproduced three gaps despite the previous 190 -tests passing: the journal lock sidecar could create a declared target before -execution, reverse-sync did not bind its authorization to the classified -baseline, and recovery could report confirmed while its fresh plan reported -drift. The reviewed plan and ablation record are in -[milestones/m3-followup.md](milestones/m3-followup.md). - -The follow-up adds the lock path to preflight, binds a private baseline digest -to the actual classifier input, rechecks authorization around source writes, -and combines recovery metadata checks with the current plan state. These -changes preserve the existing manifest versions and metadata-only output; -their stable behavior is defined in [reference.md](reference.md). - -Independent logic/value reviews identified the gaps and reviewed the plan; -the final independent code review found no remaining blocking issue in the -frozen contracts. The follow-up adds 23 tests, including baseline ABA binding, -pre/post-commit input changes, lock collisions with declared paths, metadata- -preserving content drift, unknown-state recovery, and CLI redaction/outcomes. -M3a, M3b, and M3c are implemented within their frozen scopes. At that -historical point, M4 provider, secret, portability, and operational work -remained unstarted; the current M4 closure is recorded above. - -## Historical 2026-09-14 execution and conflict closure - -The next audit started from freshly fetched `origin/master` at `d9d7092`. -Its 213 passing tests did not cover three additional cases: a final journal -failure losing known target commits, standalone unattempted recovery being -reported as confirmed, and reverse-sync proceeding past an unselected field -conflict. The reviewed plan, ablation and completion audit are maintained in -[milestones/m3-execution-closure.md](milestones/m3-execution-closure.md). - -The implementation now separates target outcomes from journal publication, -retains execution metadata even if journal diagnostics fail, requires every -resource to be confirmed for successful recovery, and blocks reverse-sync on -resource-level review. The existing public manifest versions and persistent -journal schema are unchanged. Independent logic, consent and confidentiality -reviews found no remaining implementation blocker. The additional preflight -journal fault cases requested by final review are covered, along with -failure-marking after a known replacement and failure of journal diagnostics. - -Current verification: 243 unittest tests pass (30 added to the fetched -baseline), all three M3 ablation scripts pass, and Ruff check/format, ty, -compileall, lockfile validation, wheel/sdist build and `git diff --check` pass. -The isolated M1 CLI loop again finishes in sync with a regular mode-0644 -target. Test operations use temporary projects, not user configuration. - -The complete hook gate passes in `/tmp/luwu-m3-closure-gate-MJnGeL`, containing -every current tracked and untracked repository file. File-by-file byte -comparison verifies that the checked copy matches the working tree. This -allows formatting hooks to run without opening the original protected -`.agents` files or changing the original Git index. Hooks with no applicable -files report skipped, not test coverage. Initial dependency resolution was -blocked by sandbox DNS; authorized retries succeeded. Build artifacts are in -`/tmp/luwu-m3-execution-closure-dist/`. - -M3a, M3b and M3c are complete within their frozen contracts. At that historical -point, M4 remained unstarted; automatic replay, rollback and strong consistency -against unrelated writers remain outside the M3 closure. +Status: M4 complete within the frozen public v1-v6 contracts. Automatic replay, +rollback, and strong consistency against unrelated writers remain outside the +verified scope. + +This document owns the current implementation snapshot. It does not define +product direction, public command or manifest behavior, internal mechanisms, +or historical closure evidence. See [product](product.md), +[reference](reference.md), [design](design.md), and the +[milestone records](milestones/) for those subjects. + +## Current capability matrix + +| Area | Current status | Authority and evidence | +| ------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| M1 preview | Implemented | The single-resource template and symbolic loop is covered by the M1 contract in [reference](reference.md) and the M1 closure record | +| M2 observation | Implemented | Multi-resource observation, literal copy, and strict JSON comparison remain read-only under the M2 contract | +| M3a ownership observation | Implemented | Public JSON field observation, baseline classification, ownership decisions, and undeclared-change reporting are implemented within the v3 contract | +| M3b selective mutation | Implemented | Explicit baseline acceptance and literal-JSON reverse sync are implemented within the v4 contract | +| M3c execution | Implemented | Public whole-file execution, metadata-only records, partial outcomes, and read-only recovery are implemented within the v5 contract | +| M4 provider execution | Implemented | The independent v6 provider, secret-target, metadata-cache, and platform-fail-closed paths are implemented within the v6 contract | + +The exact fields, states, error codes, output projections, compatibility +behavior, and unsupported cases are owned only by [reference](reference.md). +The rows above are status claims, not a second contract. + +## Verified scope and limits + +The latest recorded M4 closure is in +[milestones/m4.md](milestones/m4.md). Earlier M3 repair and execution evidence +is preserved in the linked M3 milestone records. Those records contain dated +commands, test counts, temporary artifact paths, and historical counterexamples; +they are not current status and are not repeated here. + +The implementation does not claim: + +- automatic replay, rollback, or recovery mutation; +- exact reviewed-plan consent tokens; +- strong consistency against writers that ignore Luwu's advisory locks; +- network providers or a broad platform matrix beyond the verified contract. + +When code or tests change, refresh this snapshot from current evidence. Do not +carry a historical completion statement forward without rerunning or +explicitly revalidating the relevant gate. diff --git a/prek.toml b/prek.toml index c35369a..543cdfc 100644 --- a/prek.toml +++ b/prek.toml @@ -47,7 +47,7 @@ priority = 2 [[repos]] repo = "https://github.com/astral-sh/uv-pre-commit" -rev = "856f55170f70dc7523c45a215ecdedc44709e2a6" # frozen: 0.12.6 +rev = "0.12.17" [[repos.hooks]] id = "uv-lock" @@ -55,21 +55,21 @@ args = ["--check"] [[repos]] repo = "https://github.com/abravalheri/validate-pyproject" -rev = "4b2e70d08cb2ccd26d1fba73588de41c7a5d50b7" # frozen: v0.25 +rev = "0.26" [[repos.hooks]] id = "validate-pyproject" [[repos]] repo = "https://github.com/gitleaks/gitleaks" -rev = "fb5d707e08fe0d2578b155458fdd53b6782dcab2" # frozen: v8.29.1 +rev = "v8.30.1" [[repos.hooks]] id = "gitleaks" [[repos]] repo = "https://github.com/astral-sh/ruff-pre-commit" -rev = "aab412d509121cb5f7533134b7e67f9fab59c682" # frozen: v0.16.4 +rev = "v0.16.8" [[repos.hooks]] id = "ruff-check" @@ -83,7 +83,7 @@ require_serial = true [[repos]] repo = "https://github.com/astral-sh/ty-pre-commit" -rev = "1241d80d7f628b8b0c60540b7a8c83b947136a4f" # frozen: v0.0.74 +rev = "v0.0.82" [[repos.hooks]] id = "ty" @@ -94,9 +94,14 @@ require_serial = true [[repos]] repo = "https://github.com/hukkin/mdformat" -rev = "82912cdaea4fb830f751504486a7879c70526547" # frozen: 1.0.0 +rev = "1.0.0" [[repos.hooks]] id = "mdformat" args = ["--wrap", "keep"] -additional_dependencies = ["mdformat-gfm==1.0.0"] +# The front-matter plugin keeps SKILL.md metadata parseable while formatting +# the Markdown body. +additional_dependencies = [ + "mdformat-gfm==1.0.0", + "mdformat-front-matters==2.0.0", +]