Skip to content

Resolve seven open decisions from the deferred-issue audit - #330

Merged
dean0x merged 11 commits into
mainfrom
feat/deferred-audit-dispositions
Aug 27, 2026
Merged

Resolve seven open decisions from the deferred-issue audit#330
dean0x merged 11 commits into
mainfrom
feat/deferred-audit-dispositions

Conversation

@dean0x

@dean0x dean0x commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Summary

A 2026-08-26 audit verified 57 "deferred past v0.4.0" issues on roadmap tracker #69 against main. Seven items needed an owner ruling rather than engineering. All seven now have an approved disposition: four were pure tracker changes (already applied — see below), three required code or documentation work, which is what this PR contains.

Nothing here is on the v0.4.0 tag path.

Commits

# Commit Content
1 feat(cli): warn on duplicate --set / --set-string keys #200 — code, tests, docs, CHANGELOG
2 docs(spec): define the project root and disambiguate mds.json discovery #201 — spec.md §5 / §4.6 / §7.8
3 docs(readme): document the .mdsroot project-root marker #201 — README.md, SECURITY.md, example READMEs
4 docs(sourcemap): add the S-tag provenance legend #188 CX-6
5 docs(resolver): re-tag @extends attribution comments to #114 #188 CX-6
6 docs(spec): source maps shipped; document the build source-map flags spec staleness
7 docs(spec): fix duplicate section 9 numbering spec staleness — droppable
8 docs(sourcemap,resolver): scope the S9 verification claim and re-anchor the #114 reference alignment-audit fixes
9 docs(spec): retitle section 11 to "Out of Scope" spec staleness — resolves the editorial flag below
10 fix(sourcemap): guard body_clean_len subtraction with saturating_sub #219 sub-item #34
11 docs(sourcemap): correct clamp_trailing_trim doc comment for the saturating bound #219 sub-item #34 — end-state cleanup

Commit 7 is deliberately isolated and can be dropped without reworking commits 1-6.

#200 — warn on duplicate --set / --set-string keys

Repeating a key within one flag group silently kept the last value. It now warns; last-value-wins behaviour is unchanged. Using the same key in both flags remains a hard error, and that check still runs first.

Stable user-facing contract:

warning: variable 'x' is set more than once by --set; the last value wins
warning: variable 'x' is set more than once by --set-string; the last value wins

build_runtime_vars returns a RuntimeVars struct carrying the duplicated keys; a named emit_duplicate_var_warnings owns the quiet check and wraps each key as safe_inline(key) syntactically at the interpolation site (AD-224-3 / AD-224-5), which is why no ALLOWED_UNTRACED_HELPER_ARGS entry was needed — print_discipline.rs is unchanged.

Returning pre-formatted message strings was rejected: the print-discipline guard cannot follow a value across a function boundary, and a pre-existing ("build.rs", "w", …) allowlist entry would have auto-exempted the new loop, silently inheriting a justification that would then be false.

Call sites: 5 emit, 4 discard. Emitting sites run once per process; rebuild paths never call the emitter, so watch mode produces no repeated noise. dir_watch_startup calls build_runtime_vars twice — the second call discards, or directory-watch startup would double-print.

Negative controls

"Warns exactly once" passes vacuously if the warning never fires, so each perturbation was run, observed, and reverted:

Perturbation Predicted Observed
emit at watch.rs:935 I8 ≥ 3 7 — every file rebuild re-emits
emit at watch.rs:2185 I9 = 2 with no edits 2 — double-print trap confirmed
emit at watch.rs:1914 I9 grows per batch 4 after one rebuild

Tests: U1–U5 unit, I1–I9 integration. I7 covers WIRE-escaping with a hostile key, asserting non-vacuity before absence (PF-013) and using braced \u{1b} / \u{202e} escapes (PF-018).

#201 — document .mdsroot

Previously undocumented, so users hitting import-containment errors had no way to discover the fix.

There is no precedence between .git and .mdsroot — the nearest ancestor holding either marker wins. The docs state this positively and name the resulting footgun: adding .mdsroot below an existing .git narrows the containment envelope. A mechanical grep -niE 'override|priorit|takes precedence|wins over' confirms none of those words appear in the new prose.

Documented: both starting points (the compiled file's directory, or the base directory a string compile supplies), depth 256, silent fallback, marker-not-config (contents never read), resolved once per compilation, and the two governed behaviours — import containment and SMv3 sources[] relativization. mds.json discovery is an independent walk sharing only the depth constant.

The open UX question — whether find_project_root should warn or error on a missing marker — is deliberately not settled here.

#188 CX-6 — S-tag provenance legend

The S-prefixed tags in mds-core had no legend in tracked source, and S8 was actively wrong. Adds a //! legend covering S3, S6, S7, S8, plus three disambiguations:

  • S5 is not Stage 5. Proven from tracked sources only: source_map_vfs.rs names cases S5/stage-2 and S5/stage-4, pairing one S-tag with two Stage numbers. The legend states only this negative — S5's positive meaning exists solely in an untracked note the legend declares non-authoritative.
  • S9 is struck. Zero occurrences in src/ at any commit; the resource-bound work it would have named shipped untagged and is documented at each item.
  • Scope. S-prefixed source-map tags only. Names B1 because it modifies S7 — it dropped the source_map_mode gate, so Origin is now populated unconditionally (verified at evaluator.rs:653).

Three S8 comments in resolver.rs re-tagged to #114, narrowed on 2026-08-26 to exactly this remaining work, plus a fourth previously-untraceable site.

Spec staleness

  • Deleted - Source maps from the exclusions list in spec.md §11 — the section was titled "What's NOT in v0.2" at the time of that commit and is titled "Out of Scope" today, retitled later in this same PR by 34af1ca. Source maps shipped in v0.4, and §7.5 already spends ~30 lines on source-map path semantics.

  • Added --source-map, --no-source-map, --inline, --embed-sources to §7.2, with conflicts/requires traced to the clap attributes, plus build.source_map / build.embed_sources to §7.8 (required companion — the --no-source-map row references the config field).

  • Fixed the duplicate ## 9 heading. Anchor-safety re-proven before renumbering: no spec.md# link exists anywhere in-repo, and no §9§12 cross-reference exists in tracked source. All eight surviving § references still resolve.

  • Retitled the renumbered heading to the version-agnostic ## 11. Out of Scope (34af1ca). Renumbering had left ## 11. What's NOT in v0.2 — a stale version number in a v0.4 spec. The owner chose a version-agnostic title over a mechanical bump to "What's NOT in v0.4" because the section lists permanent language-design exclusions, not v0.2-era deferrals; a version-pinned heading would just go stale again every release.

A repo-wide sweep before the retitle found no TOC entry, cross-reference, or markdown anchor targeting the old heading, and confirmed no in-repo link targets spec.md#… at all. The other v0.2 mention in spec.md — the v0.2.0 - Language enrichment release entry under ## 13. Status — was deliberately left untouched: that is a legitimate version-history record, not a stale title.

#219 sub-item #34saturating_sub guard in sourcemap.rs

2a5d252 changes let body_clean_len = final_body.len() - fm_prefix_len; to saturating_sub inside pub(crate) fn finalize (crates/mds-core/src/sourcemap.rs:823). The owner confirmed this is the site the original reviewer meant — the symbol the review text named (finalize_sub) has zero occurrences in the entire git history, so the location was reconstructed and then confirmed rather than recovered.

No behavior change. body_clean_len has exactly two uses in finalize: clamp_trailing_trim(points, body_clean_len), which drops every segment when the bound is 0, and an immediately following if body_clean_len == 0 early return producing an empty SourceMap. A saturated 0 therefore yields the empty map that is already the correct result when fm_prefix_len >= final_body.len(). No regression test was added: the underflow is unreachable by design, and the acceptance criteria required only saturating_sub plus a clippy-clean build.

The issue's stale sourcemap.rs:744 anchor was re-anchored to :823 in the same pass — the S-tag legend commit in this PR shifted the file, and :744 is now the closing brace of the unrelated pub(crate) fn source_index.

Doc comment corrected (4af7ef4). The doc block on clamp_trailing_trim still described the pre-2a5d252 arithmetic:

/// `body_clean_len = final_body.len() - fm_prefix_len` is computed by the caller

It now names .saturating_sub(fm_prefix_len). No behavioral clause was added — the surrounding doc block is terse, and a caveat there would not have matched its register. Correcting it is part of leaving the end state rather than the transition: a comment describing arithmetic the caller no longer performs is exactly the residue a fix tends to leave behind.

#219 stays open for sub-item #28 (unbounded loop form in formatter.rs). This PR does not close it.

Verification

Measured at 4af7ef4cf146fee082e0f47c272afc28ff1e4ca0 — the branch head when this table was stamped — with a clean working tree (git status --porcelain empty). The results below are a claim about that commit only. Any commit landing on this branch afterwards invalidates them until the suite is re-run and this table re-stamped; read an unmatched head SHA as "unverified", not as "passing".

Gate Result
cargo fmt --all --check PASS — 0 formatting issues
cargo clippy --workspace --all-targets -- -D warnings PASS — 0 warnings, 0 errors
cargo nextest run --workspace PASS — 2122 passed, 0 skipped (10.66s)
cargo test --doc PASS — 51 passed (exact baseline; run separately because nextest skips doctests)
node scripts/verify-no-control-bytes.mjs PASS — 531 files / 5,712,107 bytes scanned, clean
npm run test:gates PASS — 41 suites, 150 tests, 0 failed

The doctest count is load-bearing: an unadorned ``` fence inside a //! comment compiles as a doctest, so the legend commit had to leave the count identical, not merely passing.

An alignment audit checked all 19 negative constraints and 10 positive requirements by reading diffs rather than commit messages. It found two real defects, fixed in commit 8:

  1. The S9 zero-occurrence claim was falsified by the very commit that wrote it — rerunning the stated verification returned hits from the legend text itself. Now scoped and pinned to 6d41777.
  2. (#114) was attached to a clause describing what the source-map branch already does correctly, making shipped behaviour read as deferred. Moved onto the map-off path's actual limitation.

Related Issues

Closes #200
Closes #201
Closes #188

Tracker dispositions applied separately (no code): #197 closed as not planned; #198 reframed as a feature decision and kept open; #219 sub-item #53 dropped; #214 AC1 amended to FileNotFoundError and marked satisfied. Follow-ups filed as #326, #327, #328, #329.

dean0x and others added 10 commits August 27, 2026 00:55
Resolves #200. Closes #200.

When the same variable key appears more than once within a single --set or
--set-string group, the CLI now emits a warning to stderr so the collision is
visible. The last value still wins (unchanged behaviour). Using the same key
in both --set and --set-string remains a hard error.

Warning strings (stable contract):
  warning: variable 'x' is set more than once by --set; the last value wins
  warning: variable 'x' is set more than once by --set-string; the last value wins

Shape constraint (AD-224-3 / AD-224-5):
- New RuntimeVars struct carries vars + duplicate_set_keys + duplicate_set_string_keys.
- emit_duplicate_var_warnings owns the quiet check; safe_inline(key) is written
  syntactically at the interpolation site (not hoisted) to satisfy the
  print-discipline lexical guard.

Call-site policy (9 sites):
  Emit (5): build.rs run_build, main.rs run_check, lint.rs, watch.rs:1146
            (file_watch_startup), watch.rs:2064 (dir_watch_startup)
  Discard (4): watch.rs:935 (rebuild_file), watch.rs:1789 (rebuild_dir_batch),
               watch.rs:1914 (handle_dir_event), watch.rs:2185 (dir_watch_startup
               baseline — double-print trap; I9 is the sole mechanical guard)

Negative-control observations (I8/I9):
  Perturbation 1 (emit at :935): I8 count rose to 7 (expected >= 3).
  Perturbation 2 (emit at :2185): I9 count became 2 with no edits (expected 2).
  Perturbation 3 (emit at :1914): I9 count grew to 4 after one rebuild (expected >= 2).
  All three perturbations reverted; I8/I9 pass clean.

Tests added: U1-U5 (unit), I1-I9 (integration), plus cli_commands.rs stderr
assertion on the pre-existing set_flag_duplicate_key_last_wins test.
Docs: CHANGELOG [Unreleased]/Added, spec.md §7.2/§7.5, README.md, 8 clap doc
comments.
Adds §5 "Project Root" subsection explaining the .mdsroot/.git walk-up,
two starting points, the non-precedence rule between markers, the depth-256
silent fallback, and the two governed behaviours (import containment and
source-map relativization). Disambiguates §7.8 so "project root" no longer
refers informally to the repository root, and clarifies that mds.json
discovery is an independent walk whose relative paths resolve against
the config-containing directory. Adds import-containment bullet to §4.6.

Closes #201 (part)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds a new "## Project root" section explaining the containment boundary,
the walk-up discovery mechanism, when to create .mdsroot, and the
narrowing footgun. Adds a one-line cross-reference at the first mention
of multi-file templates. Extends the path-traversal bullet in SECURITY.md
to define the project root and flag .mdsroot placement as security-relevant.
Appends links to examples/source-maps/README.md and examples/python/README.md.

Closes #201

Co-Authored-By: Claude <noreply@anthropic.com>
Adds an `# S-tag provenance legend` section to the `//!` module doc in
`sourcemap.rs`.  Four tags are defined (S3, S6, S7, S8), each derived
from the call sites in tracked source only.

Three sub-sections clarify common confusion:

* `## S5 is not Stage 5` — proves via the `S5/stage-2` and
  `S5/stage-4` test case names in `source_map_vfs.rs` that the S-tag
  numbering and the Stage finalization pipeline are two independent
  schemes.  No positive meaning for S5 is stated (it lives only in an
  untracked local document).

* `## S9 is struck` — records that S9 has zero occurrences in
  `crates/mds-core/src/` in both the working tree and all of git
  history, and names where the resource-bound work it would have
  covered (segments_dropped, no_sources_content, MAX_SOURCEMAP_SEGMENTS,
  MAX_SOURCES_CONTENT_BYTES) actually shipped (untagged, documented at
  each item).

* `## Scope of this legend` — names the four files carrying S-tags,
  excludes PF-*/ADR-*/AC-* identifiers, notes the B1 modification to
  S7 (source_map_mode gate dropped, Origin now unconditional), and
  clarifies that S1/S2/S14 elsewhere are unrelated slice labels.

Doctest count: 51 before and after insertion (no new doctests
introduced by the legend).  Cargo doc: zero warnings before and after.

Closes part of #188.

Co-Authored-By: Claude <noreply@anthropic.com>
Issue #114 (narrowed on 2026-08-26) now covers the deferred per-region
source-map attribution work for @extends modules.  Three comments that
still referenced S8 for that work are re-tagged to #114:

* `ResolvedModule::prompt_map` field doc: "(S8 will add those)"
  → "(tracked as #114)"

* `finalize_extends` body: "is deferred to S8; spanless is the safe
  interim." → "is tracked as #114; spanless is the safe interim."

* `finalize_extends` Ok block: "is deferred to S8."
  → "is tracked as #114."

A fourth site — the map-off `else` branch comment at the @extends
finalize call (no S8 token, but named by #114 as the sibling path) —
gains "(#114)" at its closing line so the issue reference is traceable
without adding a new phase label.

No executable code changes; comments only.

Closes part of #188.

Co-Authored-By: Claude <noreply@anthropic.com>
C1: remove `- Source maps` from §10 deferred list (shipped in v0.4.0,
already documented in §7.5).

C2: add --source-map, --no-source-map, --inline, --embed-sources rows
to the §7.2 build options table, with conflicts-with / requires
relationships derived from the clap attributes. Add one example line to
the §7.2 code block (aligned to column 44). Messages-mode behaviour
noted: a warning is emitted at both resolver code paths and no source
map is produced.

C2b: add build.source_map (bool, default false) and build.embed_sources
(bool, default false) to the §7.8 mds.json config-field table.
--no-source-map's description references build.source_map; the table
row makes that field discoverable without chasing a flag description.

Co-Authored-By: Claude <noreply@anthropic.com>
spec.md had two sections numbered "## 9." — "Complete Example" and
"Editor Integration". Renumber so §9 through §13 are sequential:

  ## 9. Complete Example          (unchanged — first occurrence)
  ## 9. Editor Integration     →  ## 10. Editor Integration
  ### 9.1 File Association     →  ### 10.1 File Association
  ### 9.2 Frontmatter …        →  ### 10.2 Frontmatter …
  ### 9.3 MDS-Specific …       →  ### 10.3 MDS-Specific …
  ## 10. What's NOT in v0.2    →  ## 11. What's NOT in v0.2
  ## 11. Grammar Summary       →  ## 12. Grammar Summary
  ## 12. Status                →  ## 13. Status

No spec.md anchor links exist anywhere in the repo, and no §9–§12
cross-references exist in spec.md, so no in-repo link breaks.

Known follow-up: "## 11. What's NOT in v0.2" still carries a stale
version label — retitling is a separate editorial decision and is
out of scope for this commit.

Co-Authored-By: Claude <noreply@anthropic.com>
…or the #114 reference

sourcemap.rs: The S9 verification claim ("zero occurrences in the working
tree and in all of git history") was falsified by the very commit that
introduced it — commit 99fa56d added the legend text containing S9 itself,
so both the working-tree grep and git log immediately return non-empty
results. Fixed by scoping the claim: "outside this legend text, S9 has
zero occurrences" (verified against 6d41777, the revision immediately
before the legend was added), and naming 99fa56d as the sole introduction
commit. Applies PF-015 (avoid absolute completeness claims) and PF-028
(claims decay silently — re-verify before asserting).

resolver.rs: The (#114) reference on the map-off else-branch was attached
to the final sentence — "The source-map branch above keeps spans correct
by evaluating per-region with each region's own origin" — making shipped,
working behaviour read as deferred work. Moved (#114) to the limitation
clause ("no single source can attribute every node's offset"), which is the
actual scope of issue #114, and restored the final sentence to end without
a tag.
The section lists permanent language-design exclusions — no in-template
JS/TS scripting, no macros/async/streaming, no URL imports, no function
calls in @if/@for, no parenthesized sub-expressions, no negative slice()
indexing, no array element indexing. None of these were v0.2-era deferrals;
they are deliberate, indefinite design choices. A version-pinned heading
("What's NOT in v0.2") was already stale at v0.4 and would restale again
at each future release. "Out of Scope" is version-agnostic and accurate.

No cross-references to the old heading were found in any other tracked
file; no TOC or anchor links required updating.
Closes sub-item #34 of issue #219 (Rust minor cleanups from PR #196
review). The owner confirmed this is the intended site; the original
issue text named a symbol `finalize_sub` that has never existed in
repo history — the correct site is `finalize` in MapBuilder.

The underflow (fm_prefix_len > final_body.len()) is unreachable in
practice: fm_prefix_len is the byte length of a prepended frontmatter
block, which cannot exceed the total final body length under normal
compiler flow. The saturating_sub is therefore a zero-cost latent-defect
guard — if the impossible case were ever hit, it saturates to 0, which
causes clamp_trailing_trim to drop all segments and the existing
body_clean_len == 0 early-return to produce an empty SourceMap, a
correct and benign result rather than a panic.

Behaviour for all currently reachable inputs is unchanged.

Note: #219 remains open (sub-item #28 is still outstanding).
@dean0x
dean0x merged commit c8df485 into main Aug 27, 2026
22 checks passed
@dean0x
dean0x deleted the feat/deferred-audit-dispositions branch August 27, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant