Compare commits
No commits in common. "main" and "v1.4.0" have entirely different histories.
23 changed files with 1307 additions and 419 deletions
161
ACTIVE_SLICE.md
161
ACTIVE_SLICE.md
|
|
@ -1,57 +1,134 @@
|
|||
# Active slice
|
||||
# Milestone state
|
||||
|
||||
```text
|
||||
Last completed milestone: 5 - stabilization and first DocForge2 release.
|
||||
Release: 2.0.0.
|
||||
Last completed milestone: 5 — stabilization and first DocForge2 release.
|
||||
Baseline: annotated v1.4.0 release commit on main, dev, origin/main, and origin/dev.
|
||||
Active milestone: none.
|
||||
Maintenance: DocForge2 version identity and cross-identity proposal acceptance released.
|
||||
Outcome: Compatibility, determinism, recovery, security, performance, and representative task advantage are proven for the first successor release.
|
||||
Status: Complete.
|
||||
Release: 1.4.0.
|
||||
```
|
||||
|
||||
## Current state
|
||||
## Authority
|
||||
|
||||
DocForge2 `2.0.0` is the released product baseline. Current behavior is defined by the contracts
|
||||
and guides under `docs/`. `SLICE_HISTORY.md` contains DocForge2 milestone summaries only.
|
||||
This contract activated Milestone 5 from the clean, merged, and pushed Milestone 4 closeout. The
|
||||
roadmap in `/home/andraxion/.openclaw/workspace/DocForgeOutline.md` supplies direction; this file
|
||||
freezes the executable scope and acceptance criteria.
|
||||
|
||||
The release adds an explicit accepted-writer allowlist for project-owned canonical appliers.
|
||||
Same-identity application remains the default. Contributor processes receive no application tool,
|
||||
and successful receipts record both the proposal creator and applier.
|
||||
The completed release synchronizes `main` and `dev` at the documentation-bearing commit identified
|
||||
by annotated tag `v1.4.0`.
|
||||
|
||||
The live documentation set contains current product contracts, current operating guidance, and
|
||||
current successor milestone evidence. Superseded product plans and policy notes remain available
|
||||
only through repository history and are not part of normal documentation validation or retrieval.
|
||||
## Required release evidence
|
||||
|
||||
## Maintenance proof - 2026-07-31
|
||||
The release candidate must prove all of the following from maintained, reproducible gates:
|
||||
|
||||
- Replaced the historical application-decision memo with the current canonical-application
|
||||
contract.
|
||||
- Removed the predecessor chronology from the live slice history and removed the transition-only
|
||||
repository closeout page.
|
||||
- Updated the README and documentation validator to reference only current product documentation.
|
||||
- Formatting, Python lint, web lint, command-reference validation, and the 33-page documentation
|
||||
graph passed.
|
||||
- Focused adapter and changeset verification passed 45 tests plus 2 subtests.
|
||||
1. Legacy one-method adapter compatibility and the frozen package, CLI, MCP, schema, rendering,
|
||||
descriptor, result-envelope, and no-AST surfaces.
|
||||
2. Exact complete/incremental primary-graph and Logic equivalence for maintained incremental
|
||||
adapters.
|
||||
3. Deterministic adapter, worker, renderer, command-reference, configuration, and publication
|
||||
output.
|
||||
4. Detection of concurrent source mutation without publishing or serving a mixed or stale
|
||||
generation.
|
||||
5. Atomic, crash-safe derived publication and exact recovery from interrupted publication.
|
||||
6. Corrupt extraction-cache, index, attestation, receipt, fragment, and projection recovery using
|
||||
canonical sources as the authority.
|
||||
7. No stale reads after source or policy change, including generation-pinned retrieval and viewer
|
||||
behavior.
|
||||
8. Exact-hash canonical application with project-owned serialization, stale-proposal rejection,
|
||||
and post-application resynchronization.
|
||||
9. Closed policy precedence across process capability, descriptor policy, `--no-ast`, projection
|
||||
policy, worker enforcement, and viewer enforcement.
|
||||
10. Manual and portable-graph isolation, immutable package verification, bounded detached workers,
|
||||
rendering-policy enforcement, viewer-policy enforcement, and accessibility.
|
||||
11. Comparative representative task evidence with fixed questions, answer keys, provenance,
|
||||
latency, and response-size accounting for both graph-assisted and source-only workflows.
|
||||
12. A fresh-wheel and fresh-clone release rehearsal, full quality and browser gates, maintained
|
||||
benchmarks, secret scans, exact version identity, signed-off release notes, and reproducible
|
||||
release artifacts.
|
||||
|
||||
## Maintenance proof - 2026-08-02
|
||||
## Deliverables
|
||||
|
||||
- Compared exact released commit `f9a05f868eec6c35e2b74a69467459e6ff2190bf` with exact development
|
||||
commit `7b21541ab37c35dc9f3d47f631fef0c1884f9525` in isolated locked environments.
|
||||
- The development repository gate passed formatting, Ruff, web lint, strict Pyright, compilation,
|
||||
142 contract tests plus 272 subtests, 381 complete tests plus 422 subtests, three accessibility
|
||||
flows, dependency, build, documentation, and five smoke benchmark gates.
|
||||
- Compatibility passed 116 tests plus 263 subtests, concurrency and application passed 31 tests
|
||||
plus 2 subtests, recovery passed 72 tests plus 62 subtests, offline fresh-wheel adoption passed,
|
||||
reproducible artifact checks passed, and Git plus directory secret scans found no leaks.
|
||||
- All six full maintained benchmark tracks passed. Across 66 multi-sample operations, the median
|
||||
absolute development-versus-release difference was 0.71%; 65 remained within 5%, and the only
|
||||
larger difference was 0.062 ms on a 1.156 ms viewer-overview operation.
|
||||
- Reference-adapter graph and Logic evidence and representative-task semantic evidence matched the
|
||||
release exactly. All six representative tasks retained exact answers.
|
||||
- Anonymous exact-commit fresh clones of both revisions completed the full release gate offline and
|
||||
remained clean. The development rehearsal completed in 283.490 seconds versus 282.091 seconds for
|
||||
the release.
|
||||
- A maintained Milestone 5 compatibility matrix and aggregate release gate.
|
||||
- Reproducible migration, recovery, concurrency, and comparative-task evidence.
|
||||
- One authoritative package version shared by package metadata, Python, CLI, MCP, viewer manager,
|
||||
reference MCP, generated configuration, and release documentation.
|
||||
- A standard project license file, changelog or release notes, release baseline, closeout record,
|
||||
and machine-readable evidence.
|
||||
- A clean `main` merge, synchronized `main` and `dev`, annotated `v1.4.0` tag, and Forgejo release
|
||||
only after the final documentation-bearing commit passes a fresh-clone gate.
|
||||
|
||||
## Next gate
|
||||
## Fixed boundaries
|
||||
|
||||
No implementation milestone is active. Any additional product behavior, version identity change,
|
||||
release, or public integration requires its own bounded contract.
|
||||
- Preserve the `docforge` package, `docforge` CLI, `docforge-mcp`, MCP tool names, schema version 1
|
||||
surfaces, effective policy version 1, projection policy version 2, and legacy adapter entry point.
|
||||
- Preserve canonical project sources. Migration may rebuild disposable state but may not rewrite
|
||||
canonical content merely to satisfy the release.
|
||||
- Full rebuild remains the recovery and equivalence oracle.
|
||||
- Derived artifacts must fail closed on malformed, foreign, stale, oversized, or incompatible
|
||||
state.
|
||||
- Version `1.4.0` is additive relative to `1.0.0`; breaking a frozen contract requires a separately
|
||||
justified major-version decision.
|
||||
|
||||
## Exclusions
|
||||
|
||||
- No WorldForge change or benchmark.
|
||||
- No ScrapeStation change, production binding change, or production migration.
|
||||
- No legacy-repository mutation.
|
||||
- No production MCP repointing.
|
||||
- No remote render service, render farm, third-party renderer ecosystem, graph federation, or
|
||||
dedicated graph database.
|
||||
- No arbitrary adapter command execution, compiler execution, remote execution, or expanded
|
||||
launcher authority.
|
||||
- No PyPI publication unless it is separately verified as an intended existing release channel.
|
||||
|
||||
## Release sequence
|
||||
|
||||
1. Freeze and implement the compatibility, migration, recovery, concurrency, and task-evidence
|
||||
gates.
|
||||
2. Stabilize version identity, packaging, license, security, and release automation.
|
||||
3. Freeze one clean executable candidate and run the full repository, browser, benchmark,
|
||||
fresh-wheel, fresh-clone, and secret-scan gates.
|
||||
4. Close documentation atomically against that candidate and rerun documentation-only validation.
|
||||
5. Merge and push the final candidate.
|
||||
6. Rehearse from a fresh anonymous clone at the exact commit.
|
||||
7. Create and push the annotated `v1.4.0` tag and publish the Forgejo release from the verified
|
||||
artifacts.
|
||||
|
||||
The completed Milestone 4 contract and exclusions remain preserved in `SLICE_HISTORY.md`.
|
||||
|
||||
## Release-candidate evidence — 2026-07-29
|
||||
|
||||
The executable implementation is frozen at
|
||||
`d2bb95fe6190e659cf66ba57c78be53b63b53240`. The proof-bearing candidate base is
|
||||
`2b98059b44f4d46b4d4cce776f163e893c647c76`; it includes exact legacy-tag verification for the
|
||||
fresh-clone gate and four maintained aggregate derived-recovery tests.
|
||||
|
||||
The clean executable release gate passed formatting, Python and web lint, strict Pyright,
|
||||
compilation, lock and dependency checks, builds, generated documentation, three accessibility
|
||||
flows, fresh-wheel adoption, artifact reproducibility, secret scans, and the full Milestone 0
|
||||
through Milestone 4 benchmark sequence. Its exact test evidence was:
|
||||
|
||||
- 142 contract tests plus 272 subtests.
|
||||
- 371 complete tests plus 419 subtests.
|
||||
- 116 compatibility tests plus 263 subtests.
|
||||
- 29 concurrency tests plus 2 subtests.
|
||||
- 68 recovery tests plus 62 subtests.
|
||||
|
||||
The real migration gate preserves exact canonical and proposal bytes from the annotated `v1.0.0`
|
||||
lineage while rebuilding the disposable index from schema 1 to schema 3. The real-package task
|
||||
gate uses the lock-pinned `markdown-it-py 4.2.0` tree and proves exact graph-assisted and
|
||||
source-only answers for all reviewed tasks.
|
||||
|
||||
The later proof-only recovery commit adds four maintained tests without changing executable
|
||||
product code. The current recovery aggregate passes 72 tests plus 62 subtests.
|
||||
|
||||
The documentation-bearing candidate `49e1a87c138cdc63fb5abb85fc6eb2cf9f4a9d73` passed the complete
|
||||
local release gate with 378 tests plus 422 subtests, all three accessibility flows, and every
|
||||
focused and full gate above. Its final documentation-only descendant is the commit identified by
|
||||
annotated tag `v1.4.0`; that exact remote commit passes the anonymous fresh-clone rehearsal before
|
||||
tagging.
|
||||
|
||||
The public Forgejo release publishes the reproducible wheel, source distribution, and
|
||||
machine-readable release-identity evidence from the tagged commit. `main`, `dev`, `origin/main`,
|
||||
and `origin/dev` resolve to that same commit. No PyPI publication was performed.
|
||||
|
|
|
|||
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -5,17 +5,6 @@ remains in `docs/MILESTONE_*_BASELINE.md` and `docs/MILESTONE_*_CLOSEOUT.md`.
|
|||
|
||||
## Unreleased
|
||||
|
||||
## 2.0.0 - 2026-08-02
|
||||
|
||||
- Established `2.0.0` as the unambiguous package, Python, CLI, MCP, viewer-manager, and generated
|
||||
client identity for DocForge2 without changing descriptor, result, adapter, or index schemas.
|
||||
- Project-owned MCP servers can explicitly authorize a canonical applier to accept exact-hash
|
||||
changesets from additional configured proposal writers. The default remains same-identity
|
||||
application, contributor processes receive no application tool, and application receipts record
|
||||
both the proposal creator and applier.
|
||||
- Retained the full DocForge 1.4 compatibility, recovery, migration, benchmark, and reproducible
|
||||
artifact gates.
|
||||
|
||||
## 1.4.0 - 2026-07-29
|
||||
|
||||
Version `1.4.0` is the first additive DocForge2 successor release. Annotated tag `v1.4.0`
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -9,10 +9,9 @@ DocForge never treats indexed text as instructions. It does not run project buil
|
|||
compilers, Git operations, deployments, or arbitrary renderers, and it does not select projects
|
||||
globally.
|
||||
|
||||
DocForge 2.0.0 is the current stable DocForge2 release. It gives the successor product an
|
||||
unambiguous major-version identity, preserves the complete 1.4 adapter and recovery platform, and
|
||||
adds explicit cross-identity proposal acceptance for project-owned canonical appliers. Annotated
|
||||
tag `v2.0.0` identifies the synchronized release commit.
|
||||
DocForge 1.4.0 is the first stable DocForge2 successor release. It contains the complete adapter
|
||||
platform, stabilization and recovery evidence, representative real-task proof, and reproducible
|
||||
release artifacts. Annotated tag `v1.4.0` identifies the synchronized release commit.
|
||||
|
||||
## Start here
|
||||
|
||||
|
|
@ -205,7 +204,7 @@ paths.
|
|||
- [Compatibility contract](docs/COMPATIBILITY.md)
|
||||
- [Adapter authoring guide](docs/ADAPTER_AUTHORING_GUIDE.md)
|
||||
- [Incremental indexing](docs/INCREMENTAL_INDEXING.md)
|
||||
- [Canonical application](docs/CANONICAL_APPLICATION.md)
|
||||
- [Adapter application decision](docs/APPLICATION_DECISION.md)
|
||||
- [Legacy and no-AST operation](docs/LEGACY_AND_NO_AST.md)
|
||||
- [Migrating from version 1](docs/MIGRATING_FROM_V1.md)
|
||||
- [Viewer manager](docs/VIEWER_MANAGER.md)
|
||||
|
|
@ -219,7 +218,7 @@ paths.
|
|||
- [Milestone 3 baseline](docs/MILESTONE_3_BASELINE.md) and [closeout](docs/MILESTONE_3_CLOSEOUT.md)
|
||||
- [Milestone 2 baseline](docs/MILESTONE_2_BASELINE.md) and [closeout](docs/MILESTONE_2_CLOSEOUT.md)
|
||||
- [Milestone 1 baseline](docs/MILESTONE_1_BASELINE.md) and [closeout](docs/MILESTONE_1_CLOSEOUT.md)
|
||||
- [Milestone 0 baseline](docs/MILESTONE_0_BASELINE.md)
|
||||
- [Milestone 0 baseline](docs/MILESTONE_0_BASELINE.md) and [closeout](docs/MILESTONE_0_CLOSEOUT.md)
|
||||
|
||||
Historical milestone records preserve the facts and dependency observations of their frozen
|
||||
candidates. Use the current guides and contracts for present behavior.
|
||||
|
|
|
|||
1083
SLICE_HISTORY.md
1083
SLICE_HISTORY.md
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,8 @@
|
|||
# Canonical application
|
||||
# Canonical application decision
|
||||
|
||||
**Status:** Superseded by the DocForge 0.13 hash-bound application contract.
|
||||
|
||||
## Decision
|
||||
|
||||
DocForge may apply one isolated changeset to canonical project sources through an explicit,
|
||||
project-bound canonical applier. Application is available through both CLI and MCP. It is never an
|
||||
|
|
@ -13,11 +17,7 @@ files.
|
|||
- CLI requires `apply CHANGESET_ID --changeset-hash SHA256 --applier WRITER_ID`.
|
||||
- MCP registers `docforge_apply_changeset` only when the server starts with an explicit canonical
|
||||
applier identity and compatible applier implementation.
|
||||
- The changeset creator must be a configured proposal writer.
|
||||
- Application defaults to changesets created by the applier identity. A project-owned server may
|
||||
explicitly bind additional configured proposal writers that its applier is authorized to accept.
|
||||
- Cross-identity acceptance does not let the applier edit the contributor's proposal and does not
|
||||
give the contributor an application tool.
|
||||
- The changeset creator and applier identity must match a configured proposal writer.
|
||||
- The exact final changeset hash is required. Any proposal mutation invalidates an earlier
|
||||
approval.
|
||||
|
||||
|
|
@ -31,15 +31,17 @@ checks the derived index and regenerates declared render views.
|
|||
Application does not run project commands, tests, shell operations, Git, deployment, publication,
|
||||
or arbitrary renderers. Those remain with the owning project workflow.
|
||||
|
||||
## Safety contract
|
||||
## Why the earlier decision changed
|
||||
|
||||
The application boundary requires:
|
||||
The earlier DFG-9 decision preserved manual integration because there was not yet repeated evidence
|
||||
for canonical application. Later multi-project use produced recurring proposal application work,
|
||||
stale-index round trips, and an explicit user requirement for faster approved integration. The new
|
||||
contract addresses the original safety concerns with:
|
||||
|
||||
- exact changeset-hash approval;
|
||||
- startup-bound applier identity;
|
||||
- an explicit accepted-writer allowlist for any cross-identity application;
|
||||
- project-owned serializers for custom adapters;
|
||||
- canonical path and symbolic-link confinement;
|
||||
- canonical path and symlink confinement;
|
||||
- rollback and semantic round-trip verification;
|
||||
- deterministic derived-state refresh; and
|
||||
- complete separation from Git, builds, deployment, and publication.
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
Milestone 0 establishes DocForge2 as the successor repository without renaming or replacing the
|
||||
working DocForge interfaces. Compatibility changes require an explicit decision, a contract-test
|
||||
update, and migration guidance. DocForge 2.0.0 preserves that baseline and the complete 1.4
|
||||
adapter, rendering, recovery, and release surfaces recorded below.
|
||||
update, and migration guidance. DocForge 1.4.0 preserves that baseline and adds the adapter,
|
||||
rendering, recovery, and release surfaces recorded below.
|
||||
|
||||
The compatibility gate is:
|
||||
|
||||
|
|
@ -69,9 +69,9 @@ names and arguments remain supported. Additive commands, tools, and response fie
|
|||
Removing or changing an existing name, required argument, stable error code, or safety boundary
|
||||
requires an explicit compatibility decision.
|
||||
|
||||
Version `2.0.0` comes from one `docforge._version` authority. The four maintained executable
|
||||
surfaces report `docforge 2.0.0`, `docforge-mcp 2.0.0`,
|
||||
`python -m docforge.reference_mcp 2.0.0`, and `docforge-viewer-manager 2.0.0` for `--version`.
|
||||
Version `1.4.0` comes from one `docforge._version` authority. The four maintained executable
|
||||
surfaces report `docforge 1.4.0`, `docforge-mcp 1.4.0`,
|
||||
`python -m docforge.reference_mcp 1.4.0`, and `docforge-viewer-manager 1.4.0` for `--version`.
|
||||
Generated generic and adapter client configurations include and hash-bind the same
|
||||
`docforge_version`.
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ other users and ordinary path access; deliberate arbitrary tampering by another
|
|||
same operating-system UID is outside the compatibility boundary.
|
||||
|
||||
The historical `v1.0.0` release carried distribution metadata `1.0.0` while its module and MCP
|
||||
runtime reported `0.15.0`. Version 2.0.0 records that inherited mismatch in its maintained
|
||||
runtime reported `0.15.0`. Version 1.4.0 records that inherited mismatch in its maintained
|
||||
migration proof and resolves current identity through one authority. See
|
||||
[migrating from v1](MIGRATING_FROM_V1.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# DocForge 2.0 contract
|
||||
# DocForge 1.4 contract
|
||||
|
||||
## Authority boundary
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ commit when Git is available; it cannot change repository state.
|
|||
- Reference adapter configuration: `schemas/reference-adapter.schema.json`, version 1.
|
||||
- Index schema: version 3, disposable and reproducible.
|
||||
- Index attestation: schema version 1, disposable and reproducible.
|
||||
- Distribution, Python package, CLI, generic MCP, reference MCP, and viewer manager: version 2.0.0.
|
||||
- Distribution, Python package, CLI, generic MCP, reference MCP, and viewer manager: version 1.4.0.
|
||||
- Incremental extraction cache: version 1, disposable and reproducible.
|
||||
|
||||
Schema files describe the generic interchange contract. Runtime validation remains responsible for
|
||||
|
|
@ -42,8 +42,8 @@ path confinement, source hashing, relationship resolution, dependency cycles, pr
|
|||
state, and adapter-specific rules that JSON Schema cannot prove by itself.
|
||||
|
||||
`src/docforge/_version.py` is the sole package-version authority. The maintained executable
|
||||
surfaces report exactly `docforge 2.0.0`, `docforge-mcp 2.0.0`,
|
||||
`python -m docforge.reference_mcp 2.0.0`, and `docforge-viewer-manager 2.0.0` for `--version`.
|
||||
surfaces report exactly `docforge 1.4.0`, `docforge-mcp 1.4.0`,
|
||||
`python -m docforge.reference_mcp 1.4.0`, and `docforge-viewer-manager 1.4.0` for `--version`.
|
||||
Generated generic and adapter client configurations bind `docforge_version` into their validated
|
||||
hashes.
|
||||
|
||||
|
|
|
|||
|
|
@ -191,10 +191,7 @@ An explicit project integration may construct the full fixed surface only after
|
|||
confined proposal policy and startup-bound writer. Adapter proposal validators may narrow the
|
||||
writer's declared operations further. They cannot add arbitrary tools or weaken core changeset
|
||||
validation. The fixed application tool is registered only through the separate canonical applier
|
||||
gate. Application accepts only changesets created by the applier identity unless the project-owned
|
||||
factory explicitly supplies `accepted_proposal_writers`. Every accepted identity must already be a
|
||||
configured proposal writer. This allowlist permits review and acceptance across process identities;
|
||||
it does not grant proposal mutation or application tools to a contributor process.
|
||||
gate.
|
||||
|
||||
## Isolated proposal tools
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ Disposable index and cache schemas may change. Rebuild them rather than copying
|
|||
## Maintained v1.0.0 migration evidence
|
||||
|
||||
`make migration-m5` archives and executes the actual annotated `v1.0.0` release, then opens its
|
||||
fixture, index, and active proposal through DocForge 2.0.0. The frozen tag object is
|
||||
fixture, index, and active proposal through DocForge 1.4.0. The frozen tag object is
|
||||
`2d7d306a37da89f1c860c7f0be161c45386acf61`; it identifies commit
|
||||
`593c173b453236a6872d0a4e88e7a51a67a21cde`.
|
||||
|
||||
The tagged release contains an inherited identity mismatch that the migration proof records
|
||||
rather than hiding: distribution metadata says `1.0.0`, while `docforge.__version__` and the MCP
|
||||
server report `0.15.0`. DocForge 2.0.0 replaces that duplicated state with one authoritative
|
||||
server report `0.15.0`. DocForge 1.4.0 replaces that duplicated state with one authoritative
|
||||
version and requires its package and server values to agree.
|
||||
|
||||
The maintained fixture evidence is exact:
|
||||
|
|
|
|||
133
docs/MILESTONE_0_CLOSEOUT.md
Normal file
133
docs/MILESTONE_0_CLOSEOUT.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# DocForge2 Milestone 0 closeout
|
||||
|
||||
Milestone 0 establishes the public DocForge2 successor without changing the supported `docforge`
|
||||
product identity or the legacy DocForge repository.
|
||||
|
||||
## Repository state
|
||||
|
||||
- Public successor: <https://repo.andraxion.net/administrator/DocForge2>
|
||||
- Successor default branch: `main`
|
||||
- Successor development branches: `main` and `dev`
|
||||
- Local `origin`: `forgejo@repo.andraxion.net:administrator/DocForge2.git`
|
||||
- Local `legacy`: `forgejo@repo.andraxion.net:administrator/DocForge.git`
|
||||
- Legacy repository: private, nonempty, unarchived, and defaulted to `main`
|
||||
- Existing annotated tag: `v1.0.0`
|
||||
|
||||
`main` is the last completely verified milestone. `dev` is the integration branch for the next
|
||||
explicitly activated milestone and begins at the same commit. Historical development branch names
|
||||
remain in the legacy repository as v1 evidence; they are not replicated as active DocForge2
|
||||
branches.
|
||||
|
||||
No tag, release, release announcement, or production integration change was made.
|
||||
|
||||
## Preserved lineage
|
||||
|
||||
The migration began from the advanced
|
||||
`codex/language-agnostic-onboarding` tip
|
||||
`bb13258861175aafd0e6c03c1a5235cbaddf6db2`, nine linear commits beyond the legacy `main`.
|
||||
|
||||
The original seven-file no-AST working patch had SHA-256:
|
||||
|
||||
```text
|
||||
8cd10759c232cd4cf8c5eb024e31bbfed355e0be31fc3e732e1567c1a19a887e
|
||||
```
|
||||
|
||||
It was preserved in commit `6c05607` before other integration. The independent local-only adapter
|
||||
lifecycle commit `1ef76f0271bb339bc0d7eeb62f996d6d680548cb` was retained unchanged and merged by
|
||||
`15a9130`. The resulting successor `main` contains every commit that was reachable from any local
|
||||
ref before migration. No rebase, reset, squash, shallow seed, or older-remote seed was used.
|
||||
|
||||
A verified pre-migration bundle was written outside the repository:
|
||||
|
||||
```text
|
||||
/tmp/DocForge2-milestone0-candidate-20260729.bundle
|
||||
SHA-256 6cccd4ae2a65fa2d81e324e4592bee488b111942a496fb85f7ac6b8bd319ea2d
|
||||
```
|
||||
|
||||
## Legacy integrity
|
||||
|
||||
Before and after the successor push, the legacy repository advertised these exact heads:
|
||||
|
||||
```text
|
||||
Dev-Rewrite 73165c9f511485ea397aaa00c5e0047bd3e635e2
|
||||
DocForge-Dev 82b3b905212e7949c0a440879f3bf866197c3927
|
||||
codex/adapter-authoring-docs 7bc2ac1e3f7f9cf23ec4dcad108f9bb59978ca73
|
||||
codex/language-agnostic-onboarding bb13258861175aafd0e6c03c1a5235cbaddf6db2
|
||||
main 9fcafc290c5b5ee9cb83c4c3b2ff600f75210c8e
|
||||
```
|
||||
|
||||
The annotated `v1.0.0` tag object remained
|
||||
`2d7d306a37da89f1c860c7f0be161c45386acf61`, pointing to
|
||||
`593c173b453236a6872d0a4e88e7a51a67a21cde`.
|
||||
|
||||
No push, deletion, visibility change, archive operation, or default-branch change was performed
|
||||
against `legacy`.
|
||||
|
||||
## Compatibility and correctness
|
||||
|
||||
The stable guarantees are recorded in
|
||||
[`COMPATIBILITY.md`](COMPATIBILITY.md). The dedicated contract gate verifies:
|
||||
|
||||
- Distribution, package, imports, and three executable names.
|
||||
- CLI command and MCP tool names.
|
||||
- Published JSON schemas and representative runtime envelopes.
|
||||
- One-method `load_projection()` adapters.
|
||||
- Optional incremental behavior and full-projection equivalence.
|
||||
- Canonical JSON changeset hashing.
|
||||
- Complete no-AST behavior, including pre-existing Logic, viewer, and application-refresh paths.
|
||||
|
||||
The no-AST policy does not claim to inspect arbitrary adapter internals. It enforces the owner-bound
|
||||
policy at Logic publication and retrieval surfaces while preserving complete-projection and
|
||||
genuinely non-AST incremental adapters.
|
||||
|
||||
## Security and publication checks
|
||||
|
||||
Gitleaks 8.30.1 scanned reachable Git history and an exact archive of the candidate tree with full
|
||||
redaction. Both scans reported zero findings. `git fsck --full` passed. A broader filename and
|
||||
credential-pattern audit also found no high-confidence matches.
|
||||
|
||||
Forgejo repository creation used one timestamped short-lived administrator token. Forgejo accepted
|
||||
it for repository creation but returned HTTP 401 when it attempted self-deletion. The exact
|
||||
task-created token row was then validated by ID, owner, and unique name, deleted in one SQLite
|
||||
transaction, and rechecked. Zero matching temporary token rows remain.
|
||||
|
||||
The package metadata declares MIT, but the repository has no tracked standalone `LICENSE`,
|
||||
`COPYING`, or `NOTICE` file. Milestone 0 records that publication weakness without inventing or
|
||||
changing legal terms.
|
||||
|
||||
## Validation and fresh-clone proof
|
||||
|
||||
The repository-native aggregate gate is:
|
||||
|
||||
```bash
|
||||
make gate
|
||||
```
|
||||
|
||||
It passed in the working tree and in an anonymous HTTPS clone of the public successor. The
|
||||
fresh-clone proof:
|
||||
|
||||
- Selected the expected `main` commit through the public default branch.
|
||||
- Passed `git fsck --full`.
|
||||
- Recreated the Python virtual environment from `uv.lock`.
|
||||
- Recreated JavaScript dependencies with `npm ci`, with zero reported vulnerabilities.
|
||||
- Passed Ruff formatting and lint.
|
||||
- Passed HTML, rendered-manual HTML, CSS, and JavaScript lint.
|
||||
- Passed Pyright with zero diagnostics.
|
||||
- Passed Python compilation.
|
||||
- Passed 8 public-contract tests and 42 schema subtests.
|
||||
- Passed the complete 95-test and 44-subtest warning-strict suite.
|
||||
- Passed lock and dependency-tree checks.
|
||||
- Built the wheel and source distribution.
|
||||
- Passed the disposable benchmark smoke run.
|
||||
- Remained clean after validation.
|
||||
|
||||
The maintained performance evidence and known gaps are recorded in
|
||||
[`MILESTONE_0_BASELINE.md`](MILESTONE_0_BASELINE.md) and
|
||||
[`benchmarks/milestone0-2026-07-29.json`](../benchmarks/milestone0-2026-07-29.json).
|
||||
|
||||
## Scope confirmation
|
||||
|
||||
Milestone 0 made no speculative storage rewrite and introduced no self-hosting dependency.
|
||||
WorldForge and ScrapeStation were not read as benchmark fixtures or changed. No production MCP
|
||||
integration was repointed. `ManualRenderPlan`, `GraphViewPlan`, and a portable graph renderer remain
|
||||
later-milestone direction, not claimed implementation.
|
||||
|
|
@ -43,10 +43,9 @@ Capability modes are:
|
|||
- `operator`: reserved; it currently adds no tools.
|
||||
|
||||
Mode describes the maximum registered surface. Actual authority can be narrower. A descriptor must
|
||||
declare the selected writer, including allowed families and operation types. Application defaults
|
||||
to a matching configured writer, changeset creator, and canonical-applier identity. A project-owned
|
||||
server may explicitly authorize its applier to accept changesets from additional configured writers.
|
||||
A mode name cannot create a missing descriptor grant or extend that accepted-writer allowlist.
|
||||
declare the selected writer, including allowed families and operation types. Application requires
|
||||
the matching configured writer, changeset creator, and canonical-applier identity. A mode name
|
||||
cannot create a missing descriptor grant.
|
||||
|
||||
Generic generated client fragments default to read mode. Other construction paths preserve their
|
||||
documented compatible factory defaults. Treat `docforge_bootstrap.session_contract` and its actual
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ people and AI agents can search, inspect, visualize, and change through reviewab
|
|||
Canonical project files remain authoritative. The SQLite graph, previews, rendered manuals, and
|
||||
viewer processes are derived and can be rebuilt.
|
||||
|
||||
This manual describes the DocForge 2.0.0 release. The tagged `v1.0.0` baseline was the first stable
|
||||
product release. Version 2.0.0 preserves its project-scoped graph, CLI and MCP query
|
||||
This manual describes the DocForge 1.4.0 release. The tagged `v1.0.0` baseline was the first stable
|
||||
product release. Version 1.4.0 preserves its project-scoped graph, CLI and MCP query
|
||||
surfaces, hash-approved proposal application, generic and project-owned adapters, declared
|
||||
rendering, and Nodes/Flow/Web model while adding the maintained incremental, projection, adapter
|
||||
SDK, recovery, and release proofs documented below.
|
||||
|
|
@ -132,8 +132,8 @@ python -m docforge.reference_mcp --version
|
|||
python -m docforge.viewer_manager --version
|
||||
```
|
||||
|
||||
For version 2.0.0 these report `docforge 2.0.0`, `docforge-mcp 2.0.0`,
|
||||
`python -m docforge.reference_mcp 2.0.0`, and `docforge-viewer-manager 2.0.0`. Package metadata,
|
||||
For version 1.4.0 these report `docforge 1.4.0`, `docforge-mcp 1.4.0`,
|
||||
`python -m docforge.reference_mcp 1.4.0`, and `docforge-viewer-manager 1.4.0`. Package metadata,
|
||||
Python imports, generated generic and adapter configurations, and these commands share the same
|
||||
version authority.
|
||||
|
||||
|
|
@ -815,14 +815,7 @@ docforge-mcp \
|
|||
```
|
||||
|
||||
Without `--canonical-applier`, `docforge_apply_changeset` is not registered. The flag is an
|
||||
identity, not a command. Generic CLI and MCP application require the changeset creator, configured
|
||||
writer, and canonical applier to agree.
|
||||
|
||||
A project-owned adapter server can separately pass `accepted_proposal_writers` to
|
||||
`create_project_server`. This explicit allowlist lets its startup-bound applier accept an exact
|
||||
reviewed changeset from another configured contributor identity. The default remains the applier
|
||||
identity only. Accepted contributors retain their original proposal permissions and do not receive
|
||||
canonical application authority.
|
||||
identity, not a command. The changeset creator, configured writer, and canonical applier must agree.
|
||||
|
||||
Call `docforge_bootstrap` first. Its version-1 `session_contract` contains the fixed binding,
|
||||
current graph generation, effective policy, actual capabilities, render policies, prohibitions,
|
||||
|
|
@ -1310,7 +1303,7 @@ make fresh-clone-m5
|
|||
recovery, task-evidence, fresh-wheel, version, artifact, secret-scan, and benchmark suite.
|
||||
`fresh-clone-m5` anonymously clones the exact published candidate over HTTPS, fetches and verifies
|
||||
the frozen annotated `v1.0.0` migration tag, and repeats `release-gate`. Release operators use
|
||||
`make release-pretag` before creating `v2.0.0` and `make release-posttag` after the annotated tag
|
||||
`make release-pretag` before creating `v1.4.0` and `make release-posttag` after the annotated tag
|
||||
points to the exact release commit.
|
||||
|
||||
Project-specific vocabulary, extraction rules, and serialization belong in the project adapter.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
"""Single authoritative DocForge distribution and runtime version."""
|
||||
|
||||
__version__ = "2.0.0"
|
||||
__version__ = "1.4.0"
|
||||
|
|
|
|||
|
|
@ -1204,39 +1204,12 @@ class CanonicalApplicationService:
|
|||
*,
|
||||
applier_id: str | None,
|
||||
applier: CanonicalApplier | None,
|
||||
accepted_proposal_writers: tuple[str, ...] = (),
|
||||
index: ProjectIndex | None = None,
|
||||
manual_policy: ManualProjectionMode = "auto",
|
||||
) -> None:
|
||||
self.project = project
|
||||
self.applier_id = applier_id
|
||||
self.applier = applier
|
||||
if accepted_proposal_writers and (applier_id is None or applier is None):
|
||||
raise DocForgeError(
|
||||
"invalid_application_policy",
|
||||
"Accepted proposal writers require an enabled canonical applier",
|
||||
)
|
||||
configured_writers = frozenset(
|
||||
writer.writer_id for writer in project.descriptor.proposal_writers
|
||||
)
|
||||
selected_writers = (
|
||||
accepted_proposal_writers
|
||||
if accepted_proposal_writers
|
||||
else ((applier_id,) if applier_id is not None else ())
|
||||
)
|
||||
if len(set(selected_writers)) != len(selected_writers):
|
||||
raise DocForgeError(
|
||||
"invalid_application_policy",
|
||||
"Accepted proposal writer identities must be unique",
|
||||
)
|
||||
unknown_writers = sorted(set(selected_writers) - configured_writers)
|
||||
if unknown_writers:
|
||||
raise DocForgeError(
|
||||
"invalid_application_policy",
|
||||
"Accepted proposal writers must be configured for this project",
|
||||
writers=unknown_writers,
|
||||
)
|
||||
self.accepted_proposal_writers = tuple(sorted(selected_writers))
|
||||
self.changesets = ChangesetStore(project, applier_id)
|
||||
self.index = index or ProjectIndex(project)
|
||||
self.manual_policy = validate_manual_projection_mode(manual_policy)
|
||||
|
|
@ -1254,9 +1227,6 @@ class CanonicalApplicationService:
|
|||
return {
|
||||
"enabled": self.enabled,
|
||||
"applier": self.applier_id if self.enabled else None,
|
||||
"accepted_proposal_writers": (
|
||||
list(self.accepted_proposal_writers) if self.enabled else []
|
||||
),
|
||||
}
|
||||
|
||||
def apply(self, changeset_id: str, expected_changeset_hash: str) -> dict[str, object]:
|
||||
|
|
@ -1269,7 +1239,6 @@ class CanonicalApplicationService:
|
|||
changeset_id=changeset_id,
|
||||
expected_changeset_hash=expected_changeset_hash,
|
||||
applier_id=self.applier_id,
|
||||
accepted_creator_ids=frozenset(self.accepted_proposal_writers),
|
||||
application=self.applier.apply,
|
||||
)
|
||||
refresh_errors: list[dict[str, object]] = []
|
||||
|
|
|
|||
|
|
@ -598,7 +598,6 @@ class ChangesetStore:
|
|||
changeset_id: str,
|
||||
expected_changeset_hash: str,
|
||||
applier_id: str,
|
||||
accepted_creator_ids: frozenset[str] | None = None,
|
||||
application: Callable[
|
||||
[ProjectSnapshot, ProjectSnapshot, tuple[Mapping[str, object], ...]],
|
||||
dict[str, object],
|
||||
|
|
@ -629,17 +628,13 @@ class ChangesetStore:
|
|||
expected=expected_changeset_hash,
|
||||
actual=actual_hash,
|
||||
)
|
||||
accepted_creators = (
|
||||
frozenset({applier_id}) if accepted_creator_ids is None else accepted_creator_ids
|
||||
)
|
||||
if document["creator"] not in accepted_creators:
|
||||
if document["creator"] != applier_id:
|
||||
raise DocForgeError(
|
||||
"changeset_owner_conflict",
|
||||
"Canonical applier is not authorized to accept this changeset creator",
|
||||
"Canonical applier does not own this changeset",
|
||||
changeset_id=changeset_id,
|
||||
owner=document["creator"],
|
||||
applier=applier_id,
|
||||
accepted_creators=sorted(accepted_creators),
|
||||
)
|
||||
projected = ProjectSnapshot(
|
||||
descriptor=snapshot.descriptor,
|
||||
|
|
@ -685,8 +680,6 @@ class ChangesetStore:
|
|||
lifecycle=lifecycle,
|
||||
applied_from_revision=snapshot.revision,
|
||||
applied_from_source_hash=snapshot.source_hash,
|
||||
proposal_creator=document["creator"],
|
||||
applied_by=applier_id,
|
||||
**payload,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,6 @@ class DocForgeService:
|
|||
*,
|
||||
canonical_applier_id: str | None = None,
|
||||
canonical_applier: CanonicalApplier | None = None,
|
||||
accepted_proposal_writers: tuple[str, ...] = (),
|
||||
context_provider: ContextProvider = compile_context,
|
||||
tool_surface: tuple[str, ...] | None = None,
|
||||
binding_metadata: Mapping[str, object] | None = None,
|
||||
|
|
@ -189,7 +188,6 @@ class DocForgeService:
|
|||
self.project,
|
||||
applier_id=canonical_applier_id if application_enabled else None,
|
||||
applier=canonical_applier if application_enabled else None,
|
||||
accepted_proposal_writers=(accepted_proposal_writers if application_enabled else ()),
|
||||
index=self.index,
|
||||
manual_policy=self.projection_policy.manual,
|
||||
)
|
||||
|
|
@ -2110,7 +2108,6 @@ def create_project_server(
|
|||
proposal_writer: str | None = None,
|
||||
canonical_applier_id: str | None = None,
|
||||
canonical_applier: CanonicalApplier | None = None,
|
||||
accepted_proposal_writers: tuple[str, ...] = (),
|
||||
context_provider: ContextProvider = compile_context,
|
||||
binding_metadata: Mapping[str, object] | None = None,
|
||||
no_ast: bool = False,
|
||||
|
|
@ -2127,7 +2124,6 @@ def create_project_server(
|
|||
proposal_writer,
|
||||
canonical_applier_id=canonical_applier_id,
|
||||
canonical_applier=canonical_applier,
|
||||
accepted_proposal_writers=accepted_proposal_writers,
|
||||
context_provider=context_provider,
|
||||
binding_metadata=binding_metadata,
|
||||
no_ast=no_ast,
|
||||
|
|
|
|||
|
|
@ -397,9 +397,7 @@ def _load_descriptor(root: Path) -> ProjectDescriptor:
|
|||
title = require_string(document, "title", descriptor_path)
|
||||
adapter = require_string(document, "adapter", descriptor_path)
|
||||
if adapter != "generic":
|
||||
raise DocForgeError(
|
||||
"unsupported_adapter", "This project loader supports only the generic adapter"
|
||||
)
|
||||
raise DocForgeError("unsupported_adapter", "DFG-1 supports only the generic adapter")
|
||||
|
||||
sources = document.get("sources")
|
||||
derived = document.get("derived")
|
||||
|
|
|
|||
|
|
@ -328,103 +328,6 @@ class DocForgeChangesetTests(unittest.TestCase):
|
|||
self.assertFalse((root / ".docforge/changesets/.state/update-race.json").exists())
|
||||
self.assertFalse(tuple(target.parent.glob(".docforge-apply-*")))
|
||||
|
||||
def test_explicit_applier_accepts_a_configured_contributor_changeset(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = self.copy_fixture(Path(directory))
|
||||
descriptor = root / ".docforge/project.toml"
|
||||
descriptor.write_text(
|
||||
descriptor.read_text(encoding="utf-8")
|
||||
+ """
|
||||
|
||||
[[changesets.writers]]
|
||||
id = "contributor"
|
||||
families = ["guide"]
|
||||
operations = ["update"]
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
project = Project.open(root)
|
||||
proposal = ChangesetStore(project, "contributor").register(
|
||||
"contributor-update",
|
||||
[
|
||||
{
|
||||
"operation": "update",
|
||||
"node_id": "guide.workflow",
|
||||
"metadata": {"summary": "Accepted from a configured contributor."},
|
||||
"rationale": "Prove explicit cross-identity acceptance.",
|
||||
}
|
||||
],
|
||||
)
|
||||
default_service = CanonicalApplicationService(
|
||||
project,
|
||||
applier_id="alpha-editor",
|
||||
applier=GenericCanonicalApplier(project),
|
||||
)
|
||||
|
||||
with self.assertRaises(DocForgeError) as denied:
|
||||
default_service.apply(
|
||||
"contributor-update",
|
||||
str(proposal["changeset_hash"]),
|
||||
)
|
||||
|
||||
self.assertEqual("changeset_owner_conflict", denied.exception.code)
|
||||
service = CanonicalApplicationService(
|
||||
project,
|
||||
applier_id="alpha-editor",
|
||||
applier=GenericCanonicalApplier(project),
|
||||
accepted_proposal_writers=("alpha-editor", "contributor"),
|
||||
)
|
||||
result = service.apply(
|
||||
"contributor-update",
|
||||
str(proposal["changeset_hash"]),
|
||||
)
|
||||
|
||||
self.assertTrue(result["applied"])
|
||||
self.assertEqual("contributor", result["proposal_creator"])
|
||||
self.assertEqual("alpha-editor", result["applied_by"])
|
||||
self.assertEqual(
|
||||
["alpha-editor", "contributor"],
|
||||
service.access()["accepted_proposal_writers"],
|
||||
)
|
||||
workflow = next(
|
||||
node for node in project.load().nodes if node.node_id == "guide.workflow"
|
||||
)
|
||||
self.assertEqual(
|
||||
"Accepted from a configured contributor.",
|
||||
workflow.summary,
|
||||
)
|
||||
|
||||
def test_application_rejects_unknown_or_duplicate_accepted_writers(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = self.copy_fixture(Path(directory))
|
||||
project = Project.open(root)
|
||||
|
||||
with self.assertRaises(DocForgeError) as unknown:
|
||||
CanonicalApplicationService(
|
||||
project,
|
||||
applier_id="alpha-editor",
|
||||
applier=GenericCanonicalApplier(project),
|
||||
accepted_proposal_writers=("missing-writer",),
|
||||
)
|
||||
with self.assertRaises(DocForgeError) as duplicate:
|
||||
CanonicalApplicationService(
|
||||
project,
|
||||
applier_id="alpha-editor",
|
||||
applier=GenericCanonicalApplier(project),
|
||||
accepted_proposal_writers=("alpha-editor", "alpha-editor"),
|
||||
)
|
||||
with self.assertRaises(DocForgeError) as disabled:
|
||||
CanonicalApplicationService(
|
||||
project,
|
||||
applier_id=None,
|
||||
applier=None,
|
||||
accepted_proposal_writers=("alpha-editor",),
|
||||
)
|
||||
|
||||
self.assertEqual("invalid_application_policy", unknown.exception.code)
|
||||
self.assertEqual("invalid_application_policy", duplicate.exception.code)
|
||||
self.assertEqual("invalid_application_policy", disabled.exception.code)
|
||||
|
||||
def test_canonical_create_and_delete_races_preserve_foreign_targets(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
parent = Path(directory)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ from mcp import ClientSession, StdioServerParameters
|
|||
from mcp.client.stdio import stdio_client
|
||||
from mcp.shared.memory import create_connected_server_and_client_session
|
||||
|
||||
from docforge.application import GenericCanonicalApplier
|
||||
from docforge.changesets import ChangesetStore
|
||||
from docforge.errors import DocForgeError
|
||||
from docforge.index import ProjectIndex
|
||||
|
|
@ -30,7 +29,6 @@ from docforge.mcp_server import (
|
|||
SERVER_VERSION,
|
||||
DocForgeService,
|
||||
_create_bound_server,
|
||||
create_project_server,
|
||||
create_server,
|
||||
)
|
||||
from docforge.project import Project, project_root_fingerprint
|
||||
|
|
@ -1448,83 +1446,6 @@ class DocForgeMcpTests(unittest.IsolatedAsyncioTestCase):
|
|||
self.assertEqual("Applied through the gated MCP tool.", workflow.summary)
|
||||
self.assertTrue((root / ".docforge/rendered/manual.html").is_file())
|
||||
|
||||
async def test_project_server_accepts_an_explicit_contributor_without_granting_apply(
|
||||
self,
|
||||
) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = self.copy_fixture("alpha", Path(directory))
|
||||
descriptor = root / ".docforge/project.toml"
|
||||
descriptor.write_text(
|
||||
descriptor.read_text(encoding="utf-8")
|
||||
+ """
|
||||
|
||||
[[changesets.writers]]
|
||||
id = "contributor"
|
||||
families = ["guide"]
|
||||
operations = ["update"]
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
project = Project.open(root)
|
||||
ProjectIndex(project).build()
|
||||
async with create_connected_server_and_client_session(
|
||||
create_server(
|
||||
root,
|
||||
"contributor",
|
||||
capability_mode="proposal",
|
||||
),
|
||||
raise_exceptions=True,
|
||||
) as contributor:
|
||||
contributor_tools = tuple(
|
||||
tool.name for tool in (await contributor.list_tools()).tools
|
||||
)
|
||||
registered = await contributor.call_tool(
|
||||
"docforge_register_changes",
|
||||
{
|
||||
"changeset_id": "accepted-contribution",
|
||||
"operations": [
|
||||
{
|
||||
"operation": "update",
|
||||
"node_id": "guide.workflow",
|
||||
"metadata": {"summary": "Accepted through a separate applier."},
|
||||
"rationale": "Prove explicit contributor acceptance over MCP.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
async with create_connected_server_and_client_session(
|
||||
create_project_server(
|
||||
project,
|
||||
proposal_writer="alpha-editor",
|
||||
canonical_applier_id="alpha-editor",
|
||||
canonical_applier=GenericCanonicalApplier(project),
|
||||
accepted_proposal_writers=("contributor",),
|
||||
capability_mode="application",
|
||||
),
|
||||
raise_exceptions=True,
|
||||
) as developer:
|
||||
contract = await developer.call_tool("docforge_get_contract", {})
|
||||
applied = await developer.call_tool(
|
||||
"docforge_apply_changeset",
|
||||
{
|
||||
"changeset_id": "accepted-contribution",
|
||||
"expected_changeset_hash": registered.structuredContent["changeset_hash"],
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(ALL_TOOLS, contributor_tools)
|
||||
self.assertNotIn("docforge_apply_changeset", contributor_tools)
|
||||
self.assertEqual(
|
||||
["contributor"],
|
||||
contract.structuredContent["canonical_application_access"][
|
||||
"accepted_proposal_writers"
|
||||
],
|
||||
)
|
||||
self.assertTrue(applied.structuredContent["applied"])
|
||||
self.assertEqual("contributor", applied.structuredContent["proposal_creator"])
|
||||
self.assertEqual("alpha-editor", applied.structuredContent["applied_by"])
|
||||
|
||||
async def test_stdio_transport_serves_the_same_project_bound_contract(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = self.copy_fixture("beta", Path(directory))
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class Milestone5MigrationTests(unittest.TestCase):
|
|||
evidence = build_migration_evidence()
|
||||
|
||||
self.assertEqual("v1.0.0", evidence["tag"])
|
||||
self.assertEqual("2.0.0", evidence["current"]["version"])
|
||||
self.assertEqual("1.4.0", evidence["current"]["version"])
|
||||
self.assertEqual(1, evidence["current"]["index_schema_before"])
|
||||
self.assertEqual(3, evidence["current"]["index_schema_after"])
|
||||
self.assertEqual(
|
||||
|
|
|
|||
|
|
@ -282,10 +282,10 @@ class PublicContractTests(unittest.TestCase):
|
|||
self.assertTrue(hasattr(module, name))
|
||||
|
||||
version_surfaces = {
|
||||
"docforge.cli": "docforge 2.0.0\n",
|
||||
"docforge.mcp_server": "docforge-mcp 2.0.0\n",
|
||||
"docforge.reference_mcp": "python -m docforge.reference_mcp 2.0.0\n",
|
||||
"docforge.viewer_manager": "docforge-viewer-manager 2.0.0\n",
|
||||
"docforge.cli": "docforge 1.4.0\n",
|
||||
"docforge.mcp_server": "docforge-mcp 1.4.0\n",
|
||||
"docforge.reference_mcp": "python -m docforge.reference_mcp 1.4.0\n",
|
||||
"docforge.viewer_manager": "docforge-viewer-manager 1.4.0\n",
|
||||
}
|
||||
for module_name, expected in version_surfaces.items():
|
||||
with self.subTest(module=module_name):
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ class ReleaseIdentityTests(unittest.TestCase):
|
|||
)
|
||||
|
||||
self.assertEqual(1, evidence["schema_version"])
|
||||
self.assertEqual("2.0.0", evidence["version"])
|
||||
self.assertEqual("1.4.0", evidence["version"])
|
||||
self.assertEqual(
|
||||
{
|
||||
"docforge.cli": "docforge 2.0.0",
|
||||
"docforge.mcp_server": "docforge-mcp 2.0.0",
|
||||
"docforge.reference_mcp": "python -m docforge.reference_mcp 2.0.0",
|
||||
"docforge.viewer_manager": "docforge-viewer-manager 2.0.0",
|
||||
"docforge.cli": "docforge 1.4.0",
|
||||
"docforge.mcp_server": "docforge-mcp 1.4.0",
|
||||
"docforge.reference_mcp": "python -m docforge.reference_mcp 1.4.0",
|
||||
"docforge.viewer_manager": "docforge-viewer-manager 1.4.0",
|
||||
},
|
||||
evidence["surfaces"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ REQUIRED_MILESTONE_4_PAGES = (
|
|||
Path("README.md"),
|
||||
Path("docs/ADAPTER_AUTHORING_GUIDE.md"),
|
||||
Path("docs/AGENT_INTEGRATION.md"),
|
||||
Path("docs/CANONICAL_APPLICATION.md"),
|
||||
Path("docs/APPLICATION_DECISION.md"),
|
||||
Path("docs/COMMAND_REFERENCE.md"),
|
||||
Path("docs/COMPATIBILITY.md"),
|
||||
Path("docs/CONTRACT.md"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue