specfuse-loop 0.3.10__tar.gz → 0.3.11__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.
- {specfuse_loop-0.3.10/specfuse_loop.egg-info → specfuse_loop-0.3.11}/PKG-INFO +1 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/pyproject.toml +1 -1
- specfuse_loop-0.3.11/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +2 -2
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/concepts/ralph-lineage.md +1 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/templates/WU.template.md +1 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/loop.py +1 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11/specfuse_loop.egg-info}/PKG-INFO +1 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse_loop.egg-info/SOURCES.txt +1 -0
- specfuse_loop-0.3.11/tests/test_scaffold_doc_hygiene.py +79 -0
- specfuse_loop-0.3.10/specfuse/loop/data/VERSION +0 -1
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/LICENSE +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/NOTICE +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/README.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/setup.cfg +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/getting-started.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/methodology.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/skills.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/never-touch.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/result-contract.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/security-boundaries.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/templates/GATE.template.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/verification.yml.example +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/gate_eval.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/lint_plan.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/scaffold.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_backend.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_init_integration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_learnings_query.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lifecycle_integration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_auto_archive.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_close_intermediate.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_prepare_feature.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_roadmap_add_skill.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_data_in_sync.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_docs.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_init.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_resources.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_seed_sanity.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_scaffold_wiring.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_upgrade_integration.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_wu_execution_metadata.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specfuse-loop"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.11"
|
|
8
8
|
description = "Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.11
|
|
@@ -24,7 +24,7 @@ implementation feature == a loop feature**: the receiving component's loop decom
|
|
|
24
24
|
So gates are **internal to the loop**, not orchestrator state. The orchestrator owns
|
|
25
25
|
`initiative → feature` decomposition, cross-repo dependency ordering, and the spec/generated
|
|
26
26
|
interface contracts between features; it does **not** identify gates, run `plan-next`, or hold a
|
|
27
|
-
per-gate `plan_review`. The loop owns all of that, per [`methodology.md`](methodology.md).
|
|
27
|
+
per-gate `plan_review`. The loop owns all of that, per [`methodology.md`](../methodology.md).
|
|
28
28
|
|
|
29
29
|
**Why Model B (summary).** The loop is single-repo + edit-and-commit; codegen freezes the
|
|
30
30
|
cross-repo interface (generated `emit-*`/`on-*` contracts are immutable `_generated/`), so
|
|
@@ -60,7 +60,7 @@ gates were placed in the loop instead.
|
|
|
60
60
|
|
|
61
61
|
## 3. What the loop owns (the gate layer)
|
|
62
62
|
|
|
63
|
-
Per [`methodology.md`](methodology.md): the gate cycle (plan → execute → close → review&arm), the
|
|
63
|
+
Per [`methodology.md`](../methodology.md): the gate cycle (plan → execute → close → review&arm), the
|
|
64
64
|
four-type closing sequence (`retrospective → lessons → docs → plan-next`), `plan-next` drafting
|
|
65
65
|
the next gate (never arming it), `LEARNINGS.md`, and per-gate autonomy. These are **loop-internal**
|
|
66
66
|
to each dispatched feature; the orchestrator sees only the feature's overall state (via issue
|
{specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/docs/concepts/ralph-lineage.md
RENAMED
|
@@ -50,7 +50,7 @@ independently-adoptable projects live under it:
|
|
|
50
50
|
for multi-repo, spec-first feature delivery.
|
|
51
51
|
|
|
52
52
|
The loop and the orchestrator are two execution surfaces of **one** methodology
|
|
53
|
-
(see [`methodology.md`](methodology.md)); they share the gate cycle, the
|
|
53
|
+
(see [`methodology.md`](../methodology.md)); they share the gate cycle, the
|
|
54
54
|
work-unit contract, the correlation-ID scheme, and the verification discipline.
|
|
55
55
|
The loop is the right home for work that lives in one repo or has no formal
|
|
56
56
|
spec; the orchestrator is the right home when the work genuinely spans repos and
|
|
@@ -38,7 +38,7 @@ AUTHOR-SET FIELDS — fill or override these at draft/arm time:
|
|
|
38
38
|
- `produces` — OPTIONAL. File path(s) this WU must produce; machine-enforced by the driver's
|
|
39
39
|
presence gate (FEAT-2026-0022). Lint WARN when absent on `implementation` WUs.
|
|
40
40
|
|
|
41
|
-
DRIVER-OWNED FIELDS
|
|
41
|
+
DRIVER-OWNED FIELDS - the driver writes these at outcome time; authors leave them absent:
|
|
42
42
|
<!-- driver-owned: attempts, cost_usd, input_tokens, output_tokens, duration_seconds,
|
|
43
43
|
cumulative_cost_usd, cumulative_duration_seconds, cumulative_input_tokens,
|
|
44
44
|
cumulative_output_tokens, re_arm_count, re_arm_history -->
|
|
@@ -62,7 +62,7 @@ SPECFUSE_DIR = Path(".specfuse")
|
|
|
62
62
|
REPO_ROOT = SPECFUSE_DIR.parent
|
|
63
63
|
FEATURES_DIR = SPECFUSE_DIR / "features"
|
|
64
64
|
VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
|
|
65
|
-
DRIVER_VERSION = "0.3.
|
|
65
|
+
DRIVER_VERSION = "0.3.11"
|
|
66
66
|
# Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
|
|
67
67
|
# version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
|
|
68
68
|
# the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
|
|
@@ -118,6 +118,7 @@ tests/test_roadmap_add_skill.py
|
|
|
118
118
|
tests/test_roadmap_archive_skill.py
|
|
119
119
|
tests/test_roadmap_row_parser.py
|
|
120
120
|
tests/test_scaffold_data_in_sync.py
|
|
121
|
+
tests/test_scaffold_doc_hygiene.py
|
|
121
122
|
tests/test_scaffold_docs.py
|
|
122
123
|
tests/test_scaffold_init.py
|
|
123
124
|
tests/test_scaffold_manifest.py
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2026 Specfuse Contributors
|
|
3
|
+
# Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
4
|
+
#
|
|
5
|
+
"""Issue #140 — vendored scaffold docs/templates must not carry defects that
|
|
6
|
+
trip Markdown inspections downstream.
|
|
7
|
+
|
|
8
|
+
Two genuine defects were observed in a freshly-initialized project:
|
|
9
|
+
|
|
10
|
+
1. Broken relative links to `methodology.md` from `docs/concepts/*.md`: the
|
|
11
|
+
link uses a same-directory path but `methodology.md` lives one level up in
|
|
12
|
+
`docs/`. Correct target is `../methodology.md`.
|
|
13
|
+
2. A "Bad character" parse error on the em-dash (U+2014) leading the inline
|
|
14
|
+
text of the `DRIVER-OWNED FIELDS` paragraph in `WU.template.md`.
|
|
15
|
+
|
|
16
|
+
These guards run against the CANONICAL sources (`docs/`, `.specfuse/`); the
|
|
17
|
+
byte-match drift guard in test_scaffold_data_in_sync.py keeps the vendored
|
|
18
|
+
`specfuse/loop/data/` copies in lockstep, so fixing the canonicals + re-vendoring
|
|
19
|
+
propagates the fix everywhere.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import pathlib
|
|
25
|
+
import re
|
|
26
|
+
import unittest
|
|
27
|
+
|
|
28
|
+
REPO_ROOT = pathlib.Path(__file__).parent.parent
|
|
29
|
+
DOCS = REPO_ROOT / "docs"
|
|
30
|
+
WU_TEMPLATE = REPO_ROOT / ".specfuse" / "templates" / "WU.template.md"
|
|
31
|
+
|
|
32
|
+
# Markdown inline link with a relative path target (skips absolute URLs and
|
|
33
|
+
# pure-anchor links). Captures the path portion, dropping any `#anchor`.
|
|
34
|
+
_LINK_RE = re.compile(r"\]\((?!https?://)([^)#][^)]*?)(?:#[^)]*)?\)")
|
|
35
|
+
EM_DASH = "—"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TestScaffoldDocHygiene(unittest.TestCase):
|
|
39
|
+
|
|
40
|
+
def test_docs_relative_md_links_resolve(self):
|
|
41
|
+
"""Every relative .md link in docs/ must resolve to an existing file
|
|
42
|
+
from the linking file's own directory (issue #140 defect 1)."""
|
|
43
|
+
broken: list[str] = []
|
|
44
|
+
for md in sorted(DOCS.rglob("*.md")):
|
|
45
|
+
for lineno, line in enumerate(
|
|
46
|
+
md.read_text(encoding="utf-8").splitlines(), start=1
|
|
47
|
+
):
|
|
48
|
+
for target in _LINK_RE.findall(line):
|
|
49
|
+
if not target.endswith(".md"):
|
|
50
|
+
continue
|
|
51
|
+
resolved = (md.parent / target).resolve()
|
|
52
|
+
if not resolved.is_file():
|
|
53
|
+
rel = md.relative_to(REPO_ROOT)
|
|
54
|
+
broken.append(f"{rel}:{lineno} -> {target}")
|
|
55
|
+
self.assertEqual(
|
|
56
|
+
[], broken,
|
|
57
|
+
"broken relative .md links in docs/ (fix the path):\n"
|
|
58
|
+
+ "\n".join(broken),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def test_wu_template_driver_owned_line_has_no_em_dash(self):
|
|
62
|
+
"""The DRIVER-OWNED FIELDS paragraph must not carry the U+2014 em-dash
|
|
63
|
+
that IntelliJ flags as a Bad character (issue #140 defect 2)."""
|
|
64
|
+
matches = [
|
|
65
|
+
line
|
|
66
|
+
for line in WU_TEMPLATE.read_text(encoding="utf-8").splitlines()
|
|
67
|
+
if line.startswith("DRIVER-OWNED FIELDS")
|
|
68
|
+
]
|
|
69
|
+
self.assertTrue(matches, "DRIVER-OWNED FIELDS line not found in template")
|
|
70
|
+
for line in matches:
|
|
71
|
+
self.assertNotIn(
|
|
72
|
+
EM_DASH, line,
|
|
73
|
+
"DRIVER-OWNED FIELDS line still contains the U+2014 em-dash "
|
|
74
|
+
"that trips the Markdown parser — use ' - ' instead",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
unittest.main()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.3.10
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/security-boundaries.md
RENAMED
|
File without changes
|
{specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/specfuse/loop/data/rules/verification-discipline.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfuse_loop-0.3.10 → specfuse_loop-0.3.11}/tests/test_lint_correlation_id_close_intermediate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|