Skip to content

charter refresh-suggest never finds telemetry: close writes CHARTER-NN.telemetry.yaml, refresh-suggest looks for NN-slug.telemetry.yaml #416

Description

@montfort

Versions: cli-3.43.0, fw-4.42.0 (also present on cli-3.40.0, first observed 2026-07-26)

Summary

straymark charter refresh-suggest reports (missing) for every closed Charter, in any repo that uses the CLI, because the writer and the reader disagree on the telemetry filename.

The heuristic therefore never activates. In our repo it prints Chain length (closed Charters in window): 0 with 29 telemetry files on disk and 7 closed Charters in the chain.

Root cause

Two telemetry_path_for functions that build different names:

cli/src/commands/charter/close.rs:308-321writes CHARTER-NN.telemetry.yaml, deliberately stripping the slug:

// Strip optional slug suffix to keep the telemetry filename stable across
// Charter renames: CHARTER-01-foo → CHARTER-01.telemetry.yaml.

cli/src/commands/charter/refresh_suggest.rs:133-138reads <file_stem>.telemetry.yaml, where the stem is the Charter's own filename:

/// Charters live at `.straymark/charters/<NN-slug>.md`; telemetry sits next to
/// them as `<NN-slug>.telemetry.yaml` per the convention in charter.rs.
fn telemetry_path_for(_project_root: &Path, charter: &Charter) -> Option<PathBuf> {
    let stem = charter.path.file_stem()?.to_str()?;

So for a Charter at .straymark/charters/22-fundacion-expedientes.md:

  • close writes .straymark/charters/CHARTER-22.telemetry.yaml ✅ (exists)
  • refresh-suggest looks for .straymark/charters/22-fundacion-expedientes.telemetry.yaml ❌ (never written)

Note the doc comment in refresh_suggest.rs states the <NN-slug> convention as fact — it's the stale one. STRAYMARK.md §10 and §15 document the same stale pattern, so the docs corroborate the reader, not the writer.

Reproduction

Any repo with at least one closed Charter that has telemetry:

$ ls .straymark/charters/*.telemetry.yaml | wc -l
29

$ straymark charter refresh-suggest expedientes

    charter_id                                closed_at         R<N+1>  telemetry
    ----------                                ----------        ------  ---------
    CHARTER-22-fundacion-expedientes          —                      —  (missing)
    CHARTER-23-expedientes-us1                —                      —  (missing)
    CHARTER-24-expedientes-seguimiento        —                      —  (missing)
    ...

  Heuristic
    Chain length (closed Charters in window): 0

  ℹ Chain shorter than 3 closed Charters with telemetry — heuristic not yet meaningful.

Why it matters

The refresh heuristic is precisely the mechanism that detects accumulated spec drift across a Charter chain — the problem CHARTER-CHAIN-EVOLUTION.md was written to address. It has been silently inert since the two names diverged, and the failure mode is indistinguishable from "you don't have enough closed Charters yet", so an adopter reads the message as normal and never suspects a defect. We ran a seven-Charter chain past it without the heuristic ever firing.

Suggested fix

close.rs has the better rule — a filename stable across Charter renames — so align the reader to the writer rather than the reverse: have refresh_suggest.rs derive the name from charter.frontmatter.charter_id the same way close.rs does. Factoring the canonical-name derivation into one shared helper would prevent them drifting apart again.

Falling back to the legacy <NN-slug>.telemetry.yaml when the canonical name is absent would also pick up telemetry written by older CLI versions, if any adopter has that on disk.

STRAYMARK.md §10 and §15 need the same correction — they document the name that is never produced.

Secondary observation

The heuristic block prints two different thresholds for the same condition:

    Threshold for rolling mean:               > 6
  ℹ Chain shorter than 3 closed Charters with telemetry — heuristic not yet meaningful.

> 6 and 3 may well be two distinct gates, but as rendered they read as contradictory. Worth a label that distinguishes them.


Reported from ri-ceiba (private adopter repo, ASP.NET Core / Blazor). Tracked there as FU-033.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions