documentation-engine 0.4.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/workflows/ci.yml +3 -2
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/AGENTS.md +7 -4
- documentation_engine-0.6.0/ARCHITECTURE_REVIEW_2026-09-12.md +260 -0
- documentation_engine-0.6.0/ARCHITECTURE_REVIEW_2026-09-12_SECOND_PASS.md +222 -0
- documentation_engine-0.6.0/ARCHITECTURE_REVIEW_2026-09-12_THIRD_PASS.md +175 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/CHANGELOG.md +74 -1
- documentation_engine-0.6.0/JOURNAL_RECOVERY_DESIGN_2026-09-12.md +180 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/PKG-INFO +44 -13
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/README.md +42 -11
- documentation_engine-0.6.0/SOL_WORK_PLAN_2026-09-12.md +242 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/README.md +8 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/adoption.md +9 -2
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/agent-contract.md +39 -6
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/architecture.md +72 -14
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/client-integration.md +16 -2
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/execution-handoff.md +6 -2
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/federation.md +3 -0
- documentation_engine-0.6.0/docs/interrupted-recovery.md +101 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/knowledge-promotion.md +9 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/mcp-adapter.md +49 -2
- documentation_engine-0.6.0/docs/provider-artifacts.md +133 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/provider-snapshots.md +20 -11
- documentation_engine-0.6.0/docs/retrieval-cost-measurement.md +81 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/setup-guide.md +15 -0
- documentation_engine-0.6.0/docs/source-identity.md +55 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/workspace-sources.md +8 -3
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/scripts/installed_cli_smoke.sh +24 -0
- documentation_engine-0.6.0/scripts/measure_retrieval_cost.py +480 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/__init__.py +1 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/catalog.py +5 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/cli.py +497 -666
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/federated_projection.py +3 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/journal.py +662 -142
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/mcp_server.py +208 -10
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/metadata.py +10 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/migration.py +84 -50
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/profiles.py +3 -6
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/projection.py +210 -69
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/provider.py +84 -13
- documentation_engine-0.6.0/src/docsystem/provider_artifact.py +761 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/readiness.py +23 -0
- documentation_engine-0.6.0/src/docsystem/retrieval.py +640 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/shared_finish.py +4 -10
- documentation_engine-0.6.0/src/docsystem/strict_json.py +31 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_cli.py +6 -4
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_cli_platform.py +2 -2
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_context_cli.py +63 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_execution_handoff.py +26 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_federated_projection.py +18 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_journal.py +562 -5
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_maintenance.py +70 -9
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_mcp_adapter.py +106 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_migration.py +140 -3
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_profiles.py +167 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_provider.py +3 -1
- documentation_engine-0.6.0/tests/test_provider_artifact.py +415 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_readiness.py +93 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_release_workflows.py +1 -0
- documentation_engine-0.6.0/tests/test_retrieval_measurement.py +86 -0
- documentation_engine-0.6.0/tests/test_retrieval_service.py +168 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_vertical.py +242 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_workspace.py +1 -1
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/ISSUE_TEMPLATE/adoption-finding.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/ISSUE_TEMPLATE/core-bug.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/ISSUE_TEMPLATE/docs-pattern-request.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/ISSUE_TEMPLATE/runtime-report.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/copilot-instructions.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.github/workflows/release.yml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/.gitignore +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/CLAUDE.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/CONTRIBUTING.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/LICENSE +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/SECURITY.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/adopter-reporting.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/assets/context-reduction.svg +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/context-delivery.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/context-efficiency.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/delivery-traceability.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/document-profiles.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/execution-admission.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/graph-health.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/idea-intake.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/local-state-safety.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/metadata-inventory.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/program-plans.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/releasing.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/workstream-branching.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/workstream-evidence.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/docs/workstream-lifecycle.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/execution-admission-request.json +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/execution-result.json +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/.docsystem.toml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/README.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/plan/README.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/plan/design.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/plan/review.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/generic-adopter/plan/templates/document-template.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/idea-intake-request.json +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/provider-snapshots/.docsystem.toml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/provider-snapshots/docs/README.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/provider-snapshots/docs/service-contract.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/workstream-branch-template.md +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/examples/workstream-record.json +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/pyproject.toml +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/__main__.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/admission.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/change_plan.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/config.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/delivery.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/execution.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/federation.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/graph.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/health.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/intake.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/inventory.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/lifecycle.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/maintenance.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/program_plan.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/promotion.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/sections.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/workspace.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/src/docsystem/workstream.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_admission.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_catalog.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_change_plan.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_change_plan_cli.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_config.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_delivery.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_federated_write.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_federation.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_graph.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_health.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_intake.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_inventory.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_lifecycle.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_metadata.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_program_plan.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_promotion.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_references_cli.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_sections.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/tests/test_workstream.py +0 -0
- {documentation_engine-0.4.0 → documentation_engine-0.6.0}/uv.lock +0 -0
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
version="$(uv run python -c 'import docsystem; print(docsystem.__version__)')"
|
|
48
48
|
test -f "$dist_dir/documentation_engine-${version}-py3-none-any.whl"
|
|
49
49
|
test -f "$dist_dir/documentation_engine-${version}.tar.gz"
|
|
50
|
-
uvx --from 'twine>=
|
|
50
|
+
uvx --from 'twine>=7,<8' twine check --strict "$dist_dir"/*
|
|
51
51
|
|
|
52
52
|
# Dogfooding: walk the documented adoption sequence end-to-end against
|
|
53
53
|
# the public example profile, on a scratch copy so the fixture stays
|
|
@@ -83,7 +83,8 @@ jobs:
|
|
|
83
83
|
$env:TMP = $env:RUNNER_TEMP
|
|
84
84
|
$env:TEMP = $env:RUNNER_TEMP
|
|
85
85
|
uv run pytest tests/test_cli.py tests/test_cli_platform.py `
|
|
86
|
-
tests/test_context_cli.py tests/test_mcp_adapter.py tests/test_readiness.py
|
|
86
|
+
tests/test_context_cli.py tests/test_mcp_adapter.py tests/test_readiness.py `
|
|
87
|
+
tests/test_provider_artifact.py
|
|
87
88
|
|
|
88
89
|
- name: Installed CLI UTF-8 PowerShell smoke
|
|
89
90
|
shell: pwsh
|
|
@@ -76,10 +76,13 @@ Expected git mode for `scripts/installed_cli_smoke.sh` is `100755`.
|
|
|
76
76
|
enabled worker profile, and write both the complete task contract and a
|
|
77
77
|
`WORKER_TASK_INTENT` JSON file below `.orchestrator/prompts/`.
|
|
78
78
|
- Set `intent.verification` before dispatch and pass the intent with
|
|
79
|
-
`worker run --intent-file`. The declared verification level is
|
|
80
|
-
generic or copied task prose must not broaden it.
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
`worker run --intent-file`. The declared verification level is the required
|
|
80
|
+
baseline: generic or copied task prose must not broaden it. A concrete risk
|
|
81
|
+
discovered during the task may raise the level when the broader check remains
|
|
82
|
+
within the task's permissions and authorizations; record the reason and the
|
|
83
|
+
actual level in handoff evidence. Otherwise stop with a verification
|
|
84
|
+
escalation request. A user-requested scope change still requires corrected
|
|
85
|
+
intent before continuing.
|
|
83
86
|
- Dispatch once with a stable task id. Do not spend model turns polling worker
|
|
84
87
|
state and do not dispatch a duplicate merely because a wait timed out.
|
|
85
88
|
- For a bounded wait that fits the active Codex turn, prefer one direct
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Documentation Engine architecture review
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-12
|
|
4
|
+
Reviewed package version: 0.5.0
|
|
5
|
+
Source baseline: `3f5f9cc42e1ad4da4b9d6b9fd7387e9f3dcc01f4`
|
|
6
|
+
Disposition: retain the architecture; strengthen implementation boundaries and persistence contracts before expanding its responsibilities.
|
|
7
|
+
|
|
8
|
+
## Executive assessment
|
|
9
|
+
|
|
10
|
+
The architecture is well suited to the project's published purpose: maintaining structured Markdown knowledge that remains accessible to humans and AI clients as a project grows. Stable addresses, explicit graph semantics, inspectable context selection, disposable projections and provider-neutral interfaces form a coherent foundation. The implementation contains substantial evidence that these principles guide behavior, rather than existing only in documentation.
|
|
11
|
+
|
|
12
|
+
The main weakness is the concentration of application behavior in the CLI. The project has useful domain modules, but the boundary between application services and command presentation is incomplete. Additional concerns are inconsistent write-recovery guarantees, an ambiguity between physical byte identity and normalized text identity, whole-catalog work for small reads, and coupling between otherwise optional capabilities through configuration loading.
|
|
13
|
+
|
|
14
|
+
This is a strong local documentation engine with growing architectural debt. It is not yet evidence of a scalable concurrent knowledge service. That distinction does not make its current design unsuccessful: the documented trust model, completeness rules and single-writer assumptions deliberately favor correctness and transparent failure. A rewrite, mandatory database or mandatory server is not justified by this review.
|
|
15
|
+
|
|
16
|
+
The highest-value direction is to preserve the source-of-truth and retrieval model while extracting reusable application services and making durability, identity and execution limits explicit.
|
|
17
|
+
|
|
18
|
+
## Scope and method
|
|
19
|
+
|
|
20
|
+
The assessment uses the published goals in [README](README.md), [Architecture](docs/architecture.md), [AI client integration](docs/client-integration.md), [MCP adapter](docs/mcp-adapter.md), and the related public contracts. Exploratory product ideas are not treated as approved requirements or implementation defects. Private planning documents and adopter corpora were not inspected for this review.
|
|
21
|
+
|
|
22
|
+
The review covered source-module dependencies, representative end-to-end read/context and write paths, configuration loading, projection verification, federation, provider artifacts, representative regression tests, CI and packaging configuration. It is a single-reviewer architectural assessment, not a complete security audit or a line-by-line proof of every operation.
|
|
23
|
+
|
|
24
|
+
Two isolated diagnostics exercised concrete questions about newline identity and optional configuration. They used a synthetic project in a temporary directory under `/tmp`, which was removed after execution. No project source, configuration, tests or private planning files were modified. This report is the only new repository deliverable. A pre-existing working-tree change to `AGENTS.md` was left untouched.
|
|
25
|
+
|
|
26
|
+
### Structural observations
|
|
27
|
+
|
|
28
|
+
An AST-based inventory of `src/docsystem/*.py` and `tests/test_*.py` found:
|
|
29
|
+
|
|
30
|
+
| Observation | Result | Interpretation |
|
|
31
|
+
| --- | ---: | --- |
|
|
32
|
+
| Source modules | 32 | A compact package with several distinct capabilities |
|
|
33
|
+
| Source lines, including comments and blanks | 25,020 | Scale indicator, not a quality score |
|
|
34
|
+
| Lines in `cli.py` | 9,540, or 38.1% of source | Application and presentation responsibilities are concentrated |
|
|
35
|
+
| Functions in `cli.py`, including nested definitions | 186 | The CLI is more than argument dispatch |
|
|
36
|
+
| Largest CLI functions | Parser: 922 lines; maintenance: 570; context: 363; main: 350 | Parser size alone does not explain the concentration |
|
|
37
|
+
| Test modules / test function definitions | 35 / 578 | Definitions are not collected test-case counts or coverage percentages |
|
|
38
|
+
| Test modules importing `docsystem.cli` functions | 26 | Much behavior is verified through the CLI-facing seam |
|
|
39
|
+
| Explicit intra-package import cycles found by AST inspection | 0 | The module graph has useful dependency discipline |
|
|
40
|
+
|
|
41
|
+
Dynamic imports and runtime call dependencies are outside the import-cycle observation. Test quantity alone does not establish correctness.
|
|
42
|
+
|
|
43
|
+
## Fit against the published goals
|
|
44
|
+
|
|
45
|
+
| Goal | Assessment | Evidence and qualification |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Markdown remains the source of truth | Strong | Catalogs derive from Markdown; stale/corrupt projections visibly fall back. Physical byte identity needs clarification under newline normalization. |
|
|
48
|
+
| Complete access with task-sized reads | Strong delivery design | Explicit sections, omissions, outline, known-revision and compact modes preserve inspectability. Small responses do not currently imply small server-side work. |
|
|
49
|
+
| Stable identity and explainable relationships | Strong | Document IDs, canonical section anchors, revision pins and distinct authored/observed/generated edges avoid treating every hyperlink as authority. |
|
|
50
|
+
| Provider neutrality | Strong | Base dependencies are limited to PyYAML; MCP is optional; the core does not require a model provider or orchestration runtime. |
|
|
51
|
+
| Deterministic, verifiable derived state | Strong within stated assumptions | Generation manifests, configuration fingerprints, shard verification and direct/projected parity are explicit mechanisms. |
|
|
52
|
+
| Safe adoption and preservation of authored files | Partially satisfied | Scalar-preserving migration and managed-write guards are valuable. Migration rollback does not establish crash-atomic multi-file persistence. |
|
|
53
|
+
| Optional advanced capabilities | Partial isolation | Capabilities are separated conceptually and often by module, but one configuration loader validates them all and the CLI imports/composes them together. |
|
|
54
|
+
| Sustainable growth in corpus and integrations | Promising, insufficiently demonstrated | Sharding and portable artifacts help. Common reads still materialize the catalog, and the published benchmark measures context bytes rather than latency or memory. |
|
|
55
|
+
|
|
56
|
+
## Architecture worth preserving
|
|
57
|
+
|
|
58
|
+
**One semantic implementation behind multiple clients.** The MCP adapter invokes the same CLI that ordinary consumers use, avoiding a second implementation of graph validation and projection fallback. The optional SDK and small base dependency set preserve easy local installation. See [package configuration](pyproject.toml) and [MCP invocation](src/docsystem/mcp_server.py#L30).
|
|
59
|
+
|
|
60
|
+
**Explicit evidence and omissions.** The graph distinguishes authored metadata, observed links and generated containment. Compact context merges overlapping ranges while retaining the addresses and reasons that requested them. Reverse traversal requires sufficient graph validity to support a complete answer. These choices directly support trustworthy agent context. See [graph model](src/docsystem/graph.py#L1), [compact delivery](src/docsystem/cli.py#L2992), and [context regression tests](tests/test_context_cli.py#L336).
|
|
61
|
+
|
|
62
|
+
**Verified projections with a usable fallback.** A generation is bound to configuration and derived records, and reads reject unverifiable state. Both serving paths reduce to a shared document view. The tests inspect parity, stale configurations, shard tampering and manifest tampering. See [projection loader](src/docsystem/projection.py#L667) and [parity regression](tests/test_vertical.py#L630). Those tests were inspected, not rerun here.
|
|
63
|
+
|
|
64
|
+
**Useful domain separation already exists.** Metadata, sections, graph traversal, admission, execution-result validation and lifecycle evaluation have dedicated modules. The journal has no imports from other `docsystem` modules. The absence of explicit import cycles means extraction can be incremental; the project is not an inseparable dependency knot.
|
|
65
|
+
|
|
66
|
+
**A deliberate external evidence boundary.** Provider artifacts are complete, body-free and independently verifiable. Consumers do not need to understand internal projection shards. Unavailable generations are distinguished from entity absence. See [provider artifacts](docs/provider-artifacts.md) and [artifact regressions](tests/test_provider_artifact.py#L105).
|
|
67
|
+
|
|
68
|
+
**Verification addresses real operating boundaries.** CI includes Linux tests and lint, lock/build checks, installed CLI consumption, a public adoption walkthrough, and focused Windows UTF-8 tests. See [CI](.github/workflows/ci.yml) and [installed-consumer smoke](scripts/installed_cli_smoke.sh). This review did not inspect a live CI run or claim that these configured checks currently pass.
|
|
69
|
+
|
|
70
|
+
## Findings, ordered by architectural importance
|
|
71
|
+
|
|
72
|
+
Priority denotes recommended attention, not a vulnerability severity. High means resolve the boundary before substantial adjacent expansion; medium means address it during the next relevant capability change. Each recommendation remains a proposal.
|
|
73
|
+
|
|
74
|
+
### AR-01 — Application behavior lives inside the CLI
|
|
75
|
+
|
|
76
|
+
**Priority: high. Confidence: high. Type: maintainability and integration boundary.**
|
|
77
|
+
|
|
78
|
+
The CLI owns internal document views, direct/projected adaptation, context selection and packet construction, execution-handoff assembly, maintenance policy checks and transaction coordination. These are application responsibilities as well as command behavior. For example, [`_build_execution_handoff`](src/docsystem/cli.py#L5674) binds admission, mandate snapshots and graph-derived read/review scope, while [`maintenance`](src/docsystem/cli.py#L7227) combines authorization checks and the write workflow. Neither responsibility is intrinsically tied to terminal output.
|
|
79
|
+
|
|
80
|
+
The module's size is supporting evidence, not the finding by itself. [`_load_views`](src/docsystem/cli.py#L2630) and [`_compact_content_delivery`](src/docsystem/cli.py#L2992) demonstrate that central retrieval abstractions are private CLI implementation details. Many tests appropriately exercise this surface, but another in-process adapter cannot reuse the same behavior through a documented application-service boundary.
|
|
81
|
+
|
|
82
|
+
**Consequence:** new transports or capabilities must invoke a subprocess, depend on private CLI functions, or duplicate composition logic. Changes to presentation, orchestration and invariants become harder to review independently.
|
|
83
|
+
|
|
84
|
+
**Recommendation:** incrementally extract application services for context retrieval, evidence assembly and managed maintenance. Return typed results and diagnostics; leave argument validation specific to CLI syntax, exit-code mapping and rendering in the adapter. Keep the CLI/JSON contract stable during extraction. Internal typed services need not immediately become a public Python API.
|
|
85
|
+
|
|
86
|
+
**Acceptance evidence for future work:** unchanged CLI and MCP contract fixtures, direct/projected output parity, service-level tests without captured stdout, and an import rule preventing application/domain modules from depending on command presentation.
|
|
87
|
+
|
|
88
|
+
### AR-02 — Migration and managed maintenance have different recovery models
|
|
89
|
+
|
|
90
|
+
**Priority: high. Confidence: high for the failure boundary. Type: authored-data preservation.**
|
|
91
|
+
|
|
92
|
+
[`apply_migration_plan`](src/docsystem/migration.py#L255) checks original contents, prepares sibling temporary files, and replaces destinations one at a time. Its rollback keeps original bytes in process memory and runs only when a replacement raises `OSError`. The [rollback test](tests/test_migration.py#L147) exercises a recoverable exception while that process remains alive.
|
|
93
|
+
|
|
94
|
+
If the process terminates after replacing the first file and before replacing the next, the exception handler cannot run. The result can contain both migrated and unmigrated files, and this path provides no durable migration record from which to reconstruct the transaction. Rollback itself can also fail while writing original bytes. No crash experiment was performed; the boundary follows from the control flow and volatile storage of originals.
|
|
95
|
+
|
|
96
|
+
The [architecture guide](docs/architecture.md) describes migration with an unqualified claim that a failure never leaves a partially migrated multi-file change. That exceeds what the implementation establishes. Managed maintenance separately uses an [exclusive journal operation](src/docsystem/journal.py#L706) and [persisted before/after data](src/docsystem/journal.py#L777). That is a stronger recovery foundation, although it should not be assumed to prove every power-loss guarantee either.
|
|
97
|
+
|
|
98
|
+
**Consequence:** adopters cannot infer a uniform preservation/recovery contract across source-writing commands. This matters directly to the promise to preserve existing documentation during migration.
|
|
99
|
+
|
|
100
|
+
**Recommendation:** define the distinction between exception rollback, process-crash recovery, concurrent-reader visibility and power-loss durability. Either explicitly constrain migration to its actual failure model or design a durable migration transaction using shared recovery primitives. Preserve scalar formatting and idempotence. Avoid claiming atomic visibility across multiple ordinary file replacements.
|
|
101
|
+
|
|
102
|
+
**Acceptance evidence for future work:** interruption after each durable transaction phase, partial replacement, rollback failure, concurrent source modification and recovery replay; each should have an explicit supported outcome. No fault-injection or source-write fix is included in this review.
|
|
103
|
+
|
|
104
|
+
### AR-03 — Source hashes identify normalized text rather than physical source bytes
|
|
105
|
+
|
|
106
|
+
**Priority: medium. Confidence: high; reproduced. Type: identity and traceability contract.**
|
|
107
|
+
|
|
108
|
+
The catalog reads Markdown with [`Path.read_text`](src/docsystem/catalog.py#L226), which normalizes newlines. The projection hashes that string through [`_sha`](src/docsystem/projection.py#L73), and the [verification loader](src/docsystem/projection.py#L667) repeats the same text read. Section hashes additionally join split lines with LF.
|
|
109
|
+
|
|
110
|
+
An isolated diagnostic built a projection from a valid CRLF document, rewrote only its newline encoding to LF, and verified the old projection. The raw file SHA-256 changed, but the source hash and generation remained unchanged, and the loader returned `projection current`.
|
|
111
|
+
|
|
112
|
+
This does not show lost prose, a broken dependency graph or arbitrary tampering acceptance. CRLF and LF represent the same normalized text. The issue is that the documented byte-for-byte freshness language is stronger than the implemented identity semantics, and callers may need physical byte identity for evidence or interoperability.
|
|
113
|
+
|
|
114
|
+
**Recommendation:** explicitly distinguish raw-source byte hashes, normalized document-text hashes and delivered-fragment hashes. Decide which identity each contract needs. If physical source identity is intended, hash bytes before decoding. If normalized identity is intended, name and version that contract rather than presenting it as exact file-byte identity. A change to generation semantics requires compatibility and projection-version consideration.
|
|
115
|
+
|
|
116
|
+
**Acceptance evidence for future work:** CRLF/LF, terminal newline, Unicode and direct/projected fixtures; verify both identity semantics and unchanged human-readable content.
|
|
117
|
+
|
|
118
|
+
### AR-04 — Task-sized output still performs whole-catalog work
|
|
119
|
+
|
|
120
|
+
**Priority: medium. Confidence: high for the work performed; no latency claim. Type: scalability.**
|
|
121
|
+
|
|
122
|
+
[`read_document`](src/docsystem/cli.py#L2246) calls `_load_views` before selecting one document or section. On the direct path, [`build_catalog`](src/docsystem/catalog.py#L226) reads and parses every included Markdown file. On the projected path, [`load_verified_projection`](src/docsystem/projection.py#L667) reads all included source texts, checks their hashes, loads all document shards and the reverse shards for dependency targets, then builds all document views.
|
|
123
|
+
|
|
124
|
+
For total source volume B, a small read therefore still processes source volume proportional to B and retains whole-catalog content. A sequence of separate reads repeats that work. The specialized projected reference path has narrower shard loading; the finding should not be generalized to every command.
|
|
125
|
+
|
|
126
|
+
The integrity rationale is valid: the current contract detects source drift without relying on filesystem timestamps. The [context-efficiency measurement](docs/context-efficiency.md) correctly measures returned bytes over three predefined tasks, not runtime, memory or engineering productivity.
|
|
127
|
+
|
|
128
|
+
**Consequence:** efficient model context does not establish efficient service execution. Latency and memory may become limiting on large corpora, slower filesystems or many simultaneous consumers. Their actual thresholds are unmeasured here.
|
|
129
|
+
|
|
130
|
+
**Recommendation:** establish reproducible public synthetic performance fixtures first. Then consider query-scoped document materialization, reuse of a verified snapshot across related requests, and a documented freshness protocol. Preserve complete-graph checks where the answer requires them. A timestamp shortcut alone would weaken current guarantees and is not recommended as an automatic fix.
|
|
131
|
+
|
|
132
|
+
**Acceptance evidence for future work:** cold and repeated reads, single-section versus broad context, varying corpus sizes and graph density, source/configuration drift, peak memory, and bounded concurrency. Report response bytes separately from execution cost.
|
|
133
|
+
|
|
134
|
+
### AR-05 — Optional capabilities share one configuration failure boundary
|
|
135
|
+
|
|
136
|
+
**Priority: medium. Confidence: high; reproduced. Type: capability isolation.**
|
|
137
|
+
|
|
138
|
+
[`load_config`](src/docsystem/config.py#L1315) eagerly validates maintenance, context views, profiles, traceability, workstreams, intake and admission, even for an ordinary document read. [`_admission_criteria`](src/docsystem/config.py#L1034) rejects unknown keys. A diagnostic confirmed that adding an invalid key to the otherwise unused admission table prevents configuration loading for a simple synthetic documentation project.
|
|
139
|
+
|
|
140
|
+
Rejecting malformed policy is sensible. The architectural concern is that operational optionality does not imply independent failure or evolution boundaries: an error in an advanced capability can disable basic retrieval. This is a tradeoff, not evidence that policy validation should silently be skipped.
|
|
141
|
+
|
|
142
|
+
**Recommendation:** separate core configuration types from capability-specific types and make validation dependencies explicit. Retain a full-profile validation command. Decide deliberately whether an ordinary read requires the entire profile to be valid or only its declared dependencies; never ignore malformed safety-relevant configuration implicitly. Document the choice before changing behavior.
|
|
143
|
+
|
|
144
|
+
**Acceptance evidence for future work:** focused configuration tests proving the chosen behavior for unrelated invalid capability sections, required retrieval policy, mutations and older consumers. Configuration changes must include tests under the repository rules.
|
|
145
|
+
|
|
146
|
+
### AR-06 — The MCP subprocess boundary has no explicit execution limits
|
|
147
|
+
|
|
148
|
+
**Priority: medium. Confidence: high for the implementation. Type: adapter operability.**
|
|
149
|
+
|
|
150
|
+
[`_invoke`](src/docsystem/mcp_server.py#L30) uses synchronous `subprocess.run(..., capture_output=True)` without a timeout. It buffers the result and does not expose a child-process cancellation or deadline contract. Each request starts a new CLI process and repeats its loading work.
|
|
151
|
+
|
|
152
|
+
This boundary is valuable for semantic consistency and simple installation. The concern appears when reads stall or take a long time, or when results become large: the adapter itself has no declared way to bound that operation or propagate cancellation. The surrounding host may impose its own limits; this review did not test host cancellation behavior.
|
|
153
|
+
|
|
154
|
+
**Recommendation:** define transport execution policy, structured timeout/cancellation outcomes and bounded resource handling. Consider a reusable executor around the existing CLI before introducing another semantic implementation. If a requested operation exceeds a supported delivery bound, return an explicit failure or a versioned paging mechanism; do not silently truncate source context.
|
|
155
|
+
|
|
156
|
+
**Acceptance evidence for future work:** stalled child process, cancellation, oversized output, nonzero exit with valid failure payload, Unicode diagnostics and repeated invocation. Preserve the current distinction between legitimate domain-negative results and transport failure.
|
|
157
|
+
|
|
158
|
+
## Deliberate boundaries that should not be misclassified as bugs
|
|
159
|
+
|
|
160
|
+
1. **Federation requires a complete, available source set.** [`build_federated_catalog`](src/docsystem/federation.py#L196) checks every registered source and rejects incomplete results. This supports complete cross-source graph answers. Partial or authorization-scoped queries would need a different explicit contract, not filtering after a full query.
|
|
161
|
+
2. **Visibility metadata is not authentication.** The [workspace contract](docs/workspace-sources.md) assigns untrusted-caller enforcement to filesystem or host boundaries. The existing local MCP interface should not be exposed as a multi-user service merely because its commands are read-only.
|
|
162
|
+
3. **Retained provider generations are not an indefinite archive.** [Provider retention](docs/provider-snapshots.md#pagination-and-deterministic-bytes) governs comparison availability; portable comparison of previously exported snapshot artifacts is explicitly deferred. Consumers needing long reconciliation windows must account for that limitation.
|
|
163
|
+
4. **Projection concurrency is limited by design.** The [architecture guide](docs/architecture.md#scalable-projection) states a single-writer assumption and explains retention races. It would be inappropriate to claim concurrent service readiness from atomic replacement of the current pointer alone.
|
|
164
|
+
5. **Structural evidence does not prove semantic correctness.** Revision pins, graph completeness, admission and lifecycle records can validate authored claims and lineage. They cannot determine that an architectural recommendation is true or that an agent understood the delivered text. Human/project acceptance remains meaningful.
|
|
165
|
+
|
|
166
|
+
## Recommended direction
|
|
167
|
+
|
|
168
|
+
Keep the current package usable as a local tool. Strengthen its internal boundaries in small steps, preserving public CLI/JSON behavior.
|
|
169
|
+
|
|
170
|
+
```mermaid
|
|
171
|
+
flowchart TD
|
|
172
|
+
Clients[Human and AI clients] --> MCP[MCP adapter]
|
|
173
|
+
Clients --> CLI[CLI adapter]
|
|
174
|
+
MCP -->|Current subprocess contract| CLI
|
|
175
|
+
CLI --> Services[Explicit application services]
|
|
176
|
+
Services --> Retrieval[Catalog, sections and graph]
|
|
177
|
+
Services --> Evidence[Optional evidence and policy capabilities]
|
|
178
|
+
Services --> Writes[Explicit source-write transactions]
|
|
179
|
+
Retrieval --> Markdown[Authored Markdown]
|
|
180
|
+
Retrieval --> Projection[Verified disposable projection]
|
|
181
|
+
Writes --> Markdown
|
|
182
|
+
Writes --> Journal[Recovery journal]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This is a proposed internal decomposition, not a diagram of already completed extraction. It does not require a new service process, a database, a public Python SDK or replacement of the existing MCP transport.
|
|
186
|
+
|
|
187
|
+
| Order | Proposed work | Why this order |
|
|
188
|
+
| --- | --- | --- |
|
|
189
|
+
| 1 | Decide and document migration recovery and hash-identity guarantees | These affect preservation and the meaning of evidence; avoid building new assumptions on ambiguous contracts. |
|
|
190
|
+
| 2 | Extract context application services with unchanged output fixtures | Moves the most central reusable behavior out of presentation without a broad rewrite. |
|
|
191
|
+
| 3 | Extract governed evidence and maintenance coordination | Gives optional capabilities explicit dependencies and consistent transaction entry points. |
|
|
192
|
+
| 4 | Define configuration validation boundaries and enforce module dependency rules | Reduces future coupling while keeping policy failures explicit. |
|
|
193
|
+
| 5 | Add reproducible performance evidence and adapter execution limits | Makes optimizations and deployment decisions evidence-based. |
|
|
194
|
+
|
|
195
|
+
Do not turn every optional capability into a separate package immediately. The current base dependency footprint is already small. Package separation should follow a real dependency, compatibility or runtime boundary. Preserve independent project ownership and explicit acceptance if future knowledge applications consume this engine.
|
|
196
|
+
|
|
197
|
+
## Verification record and limits
|
|
198
|
+
|
|
199
|
+
| Activity | Status | What it establishes |
|
|
200
|
+
| --- | --- | --- |
|
|
201
|
+
| Public-contract and representative source review | Completed | Evidence for the assessments above; not exhaustive behavioral validation |
|
|
202
|
+
| AST module, size and import inventory | Completed | Reported structural counts and absence of explicit import cycles in the inspected source |
|
|
203
|
+
| Synthetic newline-identity diagnostic | Completed; confirmed AR-03 | Raw bytes change while the existing normalized-text projection remains accepted |
|
|
204
|
+
| Synthetic unused-admission configuration diagnostic | Completed; confirmed AR-05 | One optional-section validation failure blocks shared configuration loading |
|
|
205
|
+
| Existing tests and CI definitions | Inspected only | Relevant regression intent exists; no assertion that those checks passed in this review |
|
|
206
|
+
| Markdown links and cited line bounds in this report | Passed | Referenced repository files and line positions exist |
|
|
207
|
+
| `git diff --check` | Passed | No whitespace errors in the tracked working-tree diff |
|
|
208
|
+
| New-report whitespace and structure check | Passed | Covers the report while it is still untracked |
|
|
209
|
+
| Full pytest and Ruff gates | **Not run** | No implementation, configuration, packaging or test changes; the report does not claim suite success |
|
|
210
|
+
| Lock/build/distribution/installed-consumer checks | **Not run** | Packaging inputs were not changed |
|
|
211
|
+
| Performance benchmarks, crash/power-loss injection and host cancellation tests | **Not run** | Performance thresholds and those failure behaviors remain explicitly unverified |
|
|
212
|
+
|
|
213
|
+
The verification scope was structural review plus two focused isolated diagnostics prompted by concrete contract questions. The diagnostics did not require modifying repository files or running a test suite. Proposed acceptance checks above describe future work, not checks completed for this report.
|
|
214
|
+
|
|
215
|
+
### Diagnostic reproduction outline
|
|
216
|
+
|
|
217
|
+
Run from an installed contributor environment. All generated source and projection state below belongs to a disposable synthetic project, not to an adopter's documentation.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from pathlib import Path
|
|
221
|
+
from tempfile import TemporaryDirectory
|
|
222
|
+
import hashlib
|
|
223
|
+
|
|
224
|
+
from docsystem.catalog import build_catalog, validate_catalog
|
|
225
|
+
from docsystem.config import DEFAULT_CONFIG, load_config
|
|
226
|
+
from docsystem.projection import (
|
|
227
|
+
build_projection,
|
|
228
|
+
load_verified_projection,
|
|
229
|
+
write_projection,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
with TemporaryDirectory(dir="/tmp") as directory:
|
|
233
|
+
root = Path(directory)
|
|
234
|
+
config_path = root / ".docsystem.toml"
|
|
235
|
+
config_path.write_text(DEFAULT_CONFIG, encoding="utf-8")
|
|
236
|
+
document = root / "plan/architecture/README.md"
|
|
237
|
+
document.parent.mkdir(parents=True)
|
|
238
|
+
lf = b"---\nid: DOC-001\nrevision: 1\n---\n# Example\n\n## Purpose\nText.\n"
|
|
239
|
+
crlf = lf.replace(b"\n", b"\r\n")
|
|
240
|
+
document.write_bytes(crlf)
|
|
241
|
+
config = load_config(root)
|
|
242
|
+
catalog = build_catalog(config)
|
|
243
|
+
assert not [x for x in validate_catalog(catalog, config) if x.severity != "warning"]
|
|
244
|
+
before = build_projection(catalog, config)
|
|
245
|
+
write_projection(config, before)
|
|
246
|
+
document.write_bytes(lf)
|
|
247
|
+
after = build_projection(build_catalog(config), config)
|
|
248
|
+
loaded, reason = load_verified_projection(config)
|
|
249
|
+
print(hashlib.sha256(crlf).digest() != hashlib.sha256(lf).digest()) # True
|
|
250
|
+
print(before["generation"] == after["generation"]) # True
|
|
251
|
+
print(loaded is not None, reason) # True, projection current
|
|
252
|
+
config_path.write_text(
|
|
253
|
+
DEFAULT_CONFIG.replace("[admission]\n", "[admission]\nunknown_option = true\n"),
|
|
254
|
+
encoding="utf-8",
|
|
255
|
+
)
|
|
256
|
+
try:
|
|
257
|
+
load_config(root)
|
|
258
|
+
except ValueError as error:
|
|
259
|
+
print(error) # admission has unknown key(s): unknown_option
|
|
260
|
+
```
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Documentation Engine architecture review — second pass
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-12
|
|
4
|
+
Package version: 0.5.0
|
|
5
|
+
Reviewed source baseline: `3f5f9cc42e1ad4da4b9d6b9fd7387e9f3dcc01f4`
|
|
6
|
+
Related assessment: [first architectural review](ARCHITECTURE_REVIEW_2026-09-12.md)
|
|
7
|
+
|
|
8
|
+
## Assessment
|
|
9
|
+
|
|
10
|
+
The second pass supports retaining the existing architecture, but changes the immediate emphasis: **consistency between capabilities should take priority over broad code reorganization**. The Markdown source model, explicit graph relationships, verifiable projections and provider-neutral adapters remain appropriate for the published goals. Their most important weakness is that different consumers reconstruct parts of the same semantic or validation model independently.
|
|
11
|
+
|
|
12
|
+
This review confirmed one profile-validation defect, one ambiguity in command-level validation guarantees, one inconsistent transport-decoding boundary, and repeated full-inventory work during complete provider export. These are more specific than the first report's concerns about module size. They show where architectural boundaries already affect observable behavior.
|
|
13
|
+
|
|
14
|
+
The findings do not justify a rewrite, a database in the document core, or a mandatory background server. They support shared semantic accessors, explicitly named validation scopes, consistent artifact decoding and preparation of immutable export queries once per operation.
|
|
15
|
+
|
|
16
|
+
## Scope and independence
|
|
17
|
+
|
|
18
|
+
This is a second pass by the same reviewer, with new hypotheses and fresh synthetic diagnostics. It is not an independent-agent endorsement of the first report. The source commit is unchanged. Existing changes to `AGENTS.md` and the first report were preserved.
|
|
19
|
+
|
|
20
|
+
The review concentrated on composition: local versus source-qualified relations, readiness versus the normal validation gate, artifact serialization versus canonical verification, and paged versus complete exports. Relevant implementation and public contracts were inspected. Private planning documents, adopter data and external services were not used.
|
|
21
|
+
|
|
22
|
+
No implementation, configuration or test files were changed. All runtime diagnostics used disposable synthetic projects under `/tmp`. This report is the only additional repository deliverable. No full test suite or performance benchmark was run.
|
|
23
|
+
|
|
24
|
+
Priority below describes recommended engineering attention, not security severity. A confirmed behavior can be a deliberate contract choice rather than a defect; those cases are identified explicitly.
|
|
25
|
+
|
|
26
|
+
## SP-01 — Source-qualified relations disappear from document-profile validation
|
|
27
|
+
|
|
28
|
+
**Priority: high. Confidence: high. Classification: confirmed behavioral defect.**
|
|
29
|
+
|
|
30
|
+
The metadata parser stores source-qualified references separately in `DocumentMetadata.federated_references`. However, the profile helpers [`_metadata_fields`](src/docsystem/profiles.py#L59) and [`_document_relations`](src/docsystem/profiles.py#L73) inspect only ordinary references and legacy references. Consequently, profile constraints depend on how a relation target is addressed, even when the authored relation is the same.
|
|
31
|
+
|
|
32
|
+
The [profile contract](docs/document-profiles.md) states that an explicit empty `allowed_relations` list allows no values and that a required semantic field must contain a valid relation value. It does not exempt qualified references from those rules.
|
|
33
|
+
|
|
34
|
+
### Observed behavior
|
|
35
|
+
|
|
36
|
+
A synthetic document of type `spec` was checked against a profile with `allowed_relations = []`:
|
|
37
|
+
|
|
38
|
+
| Authored metadata | Result of `profile-check --json` |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `depends_on: [DOC-001]` | Exit 1; `relation-not-allowed` |
|
|
41
|
+
| `depends_on: ["peer::DOC-001"]` | Exit 0; `valid: true`; no violations |
|
|
42
|
+
| Qualified value above, with `required_metadata = ["depends_on"]` also configured | Exit 1; `missing-metadata` for the authored `depends_on` field |
|
|
43
|
+
|
|
44
|
+
The diagnostic did not connect to a real second project. It established that a syntactically accepted source-qualified relation is absent from the profile's relation inventory. Resolution or availability of its remote target is a separate question; the relation should not silently disappear from local policy evaluation.
|
|
45
|
+
|
|
46
|
+
### Architectural cause and impact
|
|
47
|
+
|
|
48
|
+
[`_references`](src/docsystem/metadata.py#L166) has a richer relation model than profile evaluation consumes. A capability added to the common metadata representation has not been incorporated into every downstream semantic helper.
|
|
49
|
+
|
|
50
|
+
This is directly relevant to the goals of project-authored policy and multi-source documentation. A project can prohibit a relation but receive a successful profile check after only changing the target's address form. Conversely, a required field can be reported absent when it is authored.
|
|
51
|
+
|
|
52
|
+
**Recommendation:** expose one authoritative relation inventory that preserves relation name, target qualification, resolution state and pin information. Profile presence and allowlist checks should consume that inventory without requiring disclosure of the target body. Keep unresolved-target diagnostics separate from field absence and relation prohibition.
|
|
53
|
+
|
|
54
|
+
**Future acceptance evidence:** a matrix covering local, qualified, pinned, legacy, empty and malformed relation values against required-field and allowlist rules, including CLI/MCP and ordinary validation entry points. The existing [profile tests](tests/test_profiles.py) exercise local relations and workspace selection, but those are not equivalent to qualified relation values inside a document.
|
|
55
|
+
|
|
56
|
+
## SP-02 — Readiness and the normal quality gate validate different scopes without naming the distinction in the readiness result
|
|
57
|
+
|
|
58
|
+
**Priority: medium. Confidence: high. Classification: reproduced contract ambiguity, not proof that all reads or index writes should be blocked.**
|
|
59
|
+
|
|
60
|
+
[`validate`](src/docsystem/cli.py#L1514) combines catalog validation, graph diagnostics, document profiles, delivery policy and program-plan checks. In contrast, [`evaluate_readiness`](src/docsystem/readiness.py#L68) evaluates a narrower set of catalog/metadata/navigation conditions. [`index_projection`](src/docsystem/cli.py#L4314) also uses the narrower catalog validator.
|
|
61
|
+
|
|
62
|
+
### Observed behavior
|
|
63
|
+
|
|
64
|
+
For a structurally sound synthetic catalog containing a local `depends_on` relation forbidden by its configured profile:
|
|
65
|
+
|
|
66
|
+
| Command | Observed outcome |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `readiness --json` | Exit 0, `ready: true` |
|
|
69
|
+
| `validate` | Exit 1, `profile spec: relation-not-allowed` |
|
|
70
|
+
| `index --write` | Exit 0, projection created |
|
|
71
|
+
|
|
72
|
+
The source did not change between those calls. The same authored profile violation therefore coexists with successful readiness and a current projection.
|
|
73
|
+
|
|
74
|
+
### Interpretation
|
|
75
|
+
|
|
76
|
+
Adoption readiness, catalog indexability and policy compliance can legitimately differ. Indexing useful documents despite a policy violation may be desirable. The problem is that the machine-facing `ready` flag and suggested next action do not disclose which configured validation dimensions were omitted. A downstream agent may treat readiness or projection freshness as a broader quality endorsement than it is.
|
|
77
|
+
|
|
78
|
+
The same distinction applies to cycle diagnostics. The [agent contract](docs/agent-contract.md) explicitly makes those corpus-wide checks available through `doctor`/`validate` rather than blocking every individual reference query. That is a deliberate boundary, not a reason to reject all cyclic-document reads.
|
|
79
|
+
|
|
80
|
+
**Recommendation:** define named validation scopes and expose their coverage. For example, a readiness result could distinguish structural readiness from profile/graph/delivery checks that passed, failed or were not evaluated. Decide deliberately whether a recommendation to index should carry outstanding policy diagnostics. Do not silently widen every query to the full quality gate.
|
|
81
|
+
|
|
82
|
+
**Future acceptance evidence:** valid structure with invalid profile, invalid program plan, graph-cycle diagnostics and absent optional policy; verify both command outcomes and explicit coverage of the checks that justify each outcome.
|
|
83
|
+
|
|
84
|
+
## SP-03 — Artifact verification accepts duplicate JSON members before checking the digest
|
|
85
|
+
|
|
86
|
+
**Priority: medium. Confidence: high. Classification: reproduced interoperability and decoding-policy gap.**
|
|
87
|
+
|
|
88
|
+
[`load_and_verify_artifact`](src/docsystem/provider_artifact.py#L745) calls ordinary `json.loads` and then verifies the resulting object. Repeated JSON object members are resolved by the parser before [`verify_artifact`](src/docsystem/provider_artifact.py#L703) evaluates the schema and canonical content digest.
|
|
89
|
+
|
|
90
|
+
### Observed behavior
|
|
91
|
+
|
|
92
|
+
A valid snapshot artifact was exported. A second `schema_version` member was inserted before the genuine member:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"schema_version": 999,
|
|
97
|
+
"schema_version": 1,
|
|
98
|
+
"artifact_kind": "provider-snapshot-artifact"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The snippet illustrates the duplicate members; the actual diagnostic retained all other required fields from the complete artifact. The existing digest was not changed. `load_and_verify_artifact` still returned `valid: true`, because the parsed object retained the last `schema_version` value and therefore had the same canonical digest as before.
|
|
103
|
+
|
|
104
|
+
This is not a SHA-256 collision or signature bypass. The [artifact contract](docs/provider-artifacts.md) correctly describes a digest of canonical content and states that authentication and provenance are separate responsibilities. Whitespace differences also legitimately do not change that digest. The narrower concern is acceptance of a transport representation whose duplicate members can be interpreted differently or rejected by another consumer.
|
|
105
|
+
|
|
106
|
+
There is already a stricter precedent in the package: [`load_shared_finish_record`](src/docsystem/shared_finish.py#L59) uses [`_reject_duplicate_keys`](src/docsystem/shared_finish.py#L44). YAML metadata also rejects repeated keys. Several other JSON loaders, including [execution packets](src/docsystem/execution.py#L65), use ordinary decoding; this review did not reproduce every loader.
|
|
107
|
+
|
|
108
|
+
**Recommendation:** define a shared unambiguous JSON input policy for integrity-bearing artifacts and requests. Reject duplicate members recursively before canonicalization. Keep this separate from the documented allowance for unknown optional fields in future-compatible artifacts: unique optional fields and duplicate keys are different compatibility questions.
|
|
109
|
+
|
|
110
|
+
**Future acceptance evidence:** root and nested duplicates, duplicate digest or scope members, malformed input, and unique unknown optional fields. Confirm that strict decoding preserves the intended additive compatibility policy and deterministic error classes.
|
|
111
|
+
|
|
112
|
+
## SP-04 — Complete export rebuilds the complete entity inventory for every page
|
|
113
|
+
|
|
114
|
+
**Priority: medium. Confidence: high for repeated work; no measured latency threshold. Classification: confirmed scalability inefficiency.**
|
|
115
|
+
|
|
116
|
+
[`snapshot_artifact`](src/docsystem/provider_artifact.py#L150) assembles pages through [`_collect_pages`](src/docsystem/provider_artifact.py#L95). Each callback invokes [`snapshot_response`](src/docsystem/provider.py#L384), which rebuilds `observations(snapshot)` for the whole immutable generation before slicing a page.
|
|
117
|
+
|
|
118
|
+
The analogous [comparison response](src/docsystem/provider.py#L413) reconstructs both inventories and their comparison each time [complete comparison export](src/docsystem/provider_artifact.py#L200) asks for another page.
|
|
119
|
+
|
|
120
|
+
### Observed behavior
|
|
121
|
+
|
|
122
|
+
A synthetic snapshot with 1,104 observations required three pages at the maximum page size of 500. Instrumentation around the existing `observations` function recorded three full inventory constructions during one `snapshot_artifact` call.
|
|
123
|
+
|
|
124
|
+
| Measurement | Result |
|
|
125
|
+
| --- | ---: |
|
|
126
|
+
| Complete artifact observations | 1,104 |
|
|
127
|
+
| Maximum requested page size | 500 |
|
|
128
|
+
| Full inventory constructions during one export | 3 |
|
|
129
|
+
|
|
130
|
+
For N entities across P pages, inventory work is repeated P times. With a fixed page-size ceiling, that component can approach quadratic growth in N. This is a work-count observation, not a runtime benchmark or a claim that memory consumption is quadratic. Generation loading itself was performed once in this diagnostic.
|
|
131
|
+
|
|
132
|
+
The current [artifact regression](tests/test_provider_artifact.py#L105) covers complete multi-page output and deterministic verification. That is valuable correctness evidence, but does not constrain how often the same immutable query is prepared.
|
|
133
|
+
|
|
134
|
+
**Recommendation:** prepare and validate the immutable inventory or comparison once per complete export, then expose a page view over that prepared query. Reuse public contract semantics without repeatedly rebuilding the entire result merely to keep an internal page-shaped call boundary. Preserve ordering, cursor binding, byte limits and complete-or-fail assembly.
|
|
135
|
+
|
|
136
|
+
**Future acceptance evidence:** operation counts over increasing entity totals, complete/paged result equality, byte-limited pages, empty results and multi-page comparisons. Performance benchmarks can then determine whether additional streaming or memory changes are necessary.
|
|
137
|
+
|
|
138
|
+
## Reassessment of the first report
|
|
139
|
+
|
|
140
|
+
| First-pass finding | Second-pass disposition |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| AR-01: application logic in the CLI | Supported, with a sharper remedy. Extract ownership of shared semantics and validation before performing a mechanical file split. SP-01 and SP-02 illustrate why. |
|
|
143
|
+
| AR-02: migration recovery model | Retained as a static failure-model concern. No new crash or rollback-failure experiment was run; the second pass does not upgrade it to a reproduced crash incident. |
|
|
144
|
+
| AR-03: normalized-text hashes | Retained with the existing qualification: physical file identity and normalized text identity differ. This is not evidence of lost prose or an insecure hash algorithm. |
|
|
145
|
+
| AR-04: whole-catalog work for small reads | Supported. SP-04 identifies a separate repeated-work issue in complete provider export. Neither review establishes actual latency limits. |
|
|
146
|
+
| AR-05: shared configuration failure boundary | Treat as a design tradeoff, not an instruction to ignore invalid optional policy. Address only through an explicit validation-dependency contract. |
|
|
147
|
+
| AR-06: MCP execution limits | Supported as an adapter-operability concern. The absence of a timeout does not establish observed host failure and does not justify making a daemon mandatory. |
|
|
148
|
+
|
|
149
|
+
The first review's positive observations remain valid: a small base dependency set, no explicit intra-package import cycles in the inspected AST graph, useful domain modules, explicit context omissions and strong direct/projected parity intent in tests. These are foundations to preserve, not reasons to overlook cross-capability inconsistencies.
|
|
150
|
+
|
|
151
|
+
## Recommended order of attention
|
|
152
|
+
|
|
153
|
+
1. Correct qualified-relation handling in profile checks and add semantic-form parity coverage.
|
|
154
|
+
2. Define a consistent strict decoder for integrity-bearing JSON; retain additive field compatibility where the contract allows it.
|
|
155
|
+
3. Name and expose the validation scope behind readiness, quality gates and projection status.
|
|
156
|
+
4. Prepare complete-export inventories once; measure work counts before broad optimization.
|
|
157
|
+
5. Use these concrete boundaries to guide the application-service extraction proposed in the first review.
|
|
158
|
+
|
|
159
|
+
Migration durability and hash-identity decisions from the first report remain parallel prerequisites for expanding write automation or external traceability guarantees. No implementation or repository reorganization is authorized by this report.
|
|
160
|
+
|
|
161
|
+
## Verification record
|
|
162
|
+
|
|
163
|
+
| Activity | Outcome |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| Source baseline and existing working-tree inspection | Completed; source commit unchanged |
|
|
166
|
+
| Local versus qualified relation diagnostic | Completed; SP-01 reproduced |
|
|
167
|
+
| Qualified required-field diagnostic | Completed; SP-01 reproduced |
|
|
168
|
+
| Readiness / validate / index comparison | Completed; SP-02 reproduced on unchanged synthetic source |
|
|
169
|
+
| Duplicate-member artifact diagnostic | Completed; SP-03 reproduced with the original canonical digest |
|
|
170
|
+
| Complete-export inventory-call instrumentation | Completed; SP-04 reproduced, 3 full inventories for 1,104 observations |
|
|
171
|
+
| Relevant existing tests and public contracts | Inspected; not claimed to have passed |
|
|
172
|
+
| Report links, cited line bounds and Markdown structure | Passed |
|
|
173
|
+
| `git diff --check` and new-report whitespace validation | Passed |
|
|
174
|
+
| Preservation hashes of `AGENTS.md` and the first report | Unchanged |
|
|
175
|
+
| Full pytest / Ruff gate | **Not run** — no implementation or configuration changes |
|
|
176
|
+
| Build, lock and installed-consumer checks | **Not run** — packaging inputs unchanged |
|
|
177
|
+
| Timing, memory, cancellation and crash experiments | **Not run** |
|
|
178
|
+
|
|
179
|
+
The diagnostic examples contain only synthetic content. Their temporary files and projections were removed after execution. Model-worker orchestration was not dispatched because the existing project binding still targeted a different host task; its binding and delivery state were left unchanged. This is a scope limitation of reviewer independence, not a defect in Documentation Engine.
|
|
180
|
+
|
|
181
|
+
## Reproduction recipes
|
|
182
|
+
|
|
183
|
+
These recipes describe the isolated diagnostics, rather than proposing changes to repository fixtures. Use an existing contributor environment and disposable directories under `/tmp`.
|
|
184
|
+
|
|
185
|
+
### Profile and validation scope
|
|
186
|
+
|
|
187
|
+
Create a minimal valid catalog with `DOC-001` as its index linking to `DOC-002`. Map a root area to `.`. Give `DOC-002` the type `spec` and configure:
|
|
188
|
+
|
|
189
|
+
```toml
|
|
190
|
+
[profiles.spec]
|
|
191
|
+
document_types = ["spec"]
|
|
192
|
+
history_mode = "living"
|
|
193
|
+
allowed_relations = []
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Run `profile-check --json` first with `depends_on: [DOC-001]`, then with `depends_on: ["peer::DOC-001"]`. Add `required_metadata = ["depends_on"]` to the same profile and repeat the qualified case. Finally, restore the local relation and the profile without the required-field rule, then compare `readiness --json`, `validate` and `index --write` on the same temporary project. Expected observed results are recorded in SP-01 and SP-02.
|
|
197
|
+
|
|
198
|
+
### Complete export and duplicate members
|
|
199
|
+
|
|
200
|
+
Create a provider-enabled synthetic catalog containing an index and a target with 1,100 H2 sections. Build and retain one generation, then load it once with `load_pinned_projection`. Instrumentation used the existing implementation without changing a source file:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from unittest.mock import patch
|
|
204
|
+
import docsystem.provider as provider
|
|
205
|
+
from docsystem.provider_artifact import (
|
|
206
|
+
encode_artifact,
|
|
207
|
+
load_and_verify_artifact,
|
|
208
|
+
snapshot_artifact,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# snapshot is the pinned synthetic generation; temporary_path is under /tmp.
|
|
212
|
+
with patch.object(provider, "observations", wraps=provider.observations) as counter:
|
|
213
|
+
artifact = snapshot_artifact(snapshot)
|
|
214
|
+
print(len(artifact["observations"]), counter.call_count) # 1104, 3
|
|
215
|
+
|
|
216
|
+
encoded = encode_artifact(artifact)
|
|
217
|
+
ambiguous = encoded.replace("{", '{\n "schema_version": 999,', 1)
|
|
218
|
+
temporary_path.write_text(ambiguous, encoding="utf-8")
|
|
219
|
+
print(load_and_verify_artifact(temporary_path)["valid"]) # True
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The code is a contributor-side diagnostic of implementation behavior, not a recommendation for external consumers to import internal package modules. External integrations should continue to use the documented CLI/artifact contracts.
|