Skip to content

[adopter] Three validator gaps from a 150-doc housekeeping pass: OBS-001 false positives (19/19), exactly-one originating_* vs documented AILOG aggregation (N=5), CHARTER-FILES-EXIST exemption markers #215

@montfort

Description

@montfort

Context

Adopter experience report from StrangeDaysTech/sentinel (private repo), same series as #214. During a post-stage housekeeping pass we drove straymark validate --include-charters from 33 errors / 77 warnings → 0 errors / 32 warnings across 150 documents (sentinel PR #110, org-visible). The 32 that remain are all false positives or deliberate exceptions — and they cluster into three validator gaps worth reporting. A fourth observation about status-vocabulary drift is included as a minor note.

Gap 1 — OBS-001 heuristic: 19/19 false positives (keyword set too narrow)

Every single OBS-001 warning in our pass was a false positive — including on the AILOG that documents the project's observability bundle itself (metrics, dashboards, alert policies).

Root cause (read from cli/src/validation.rs:1205-1217): the rule requires one of

  • ## Observability / ## Observabilidad heading
  • literal substrings instrumentation / instrumentación / OpenTelemetry / observability_scope

Our documents — written in mixed ES/EN — talk about OTel, otel-collector, metrics, métricas, spans, histogram, slog, Cloud Monitoring, dashboards, alert policies. None of those literals match. A doc can enumerate twelve metric names and still "lack observability-related content".

Suggestion: widen the keyword set (OTel, lowercase opentelemetry, metric/métrica, span, trace, dashboard, collector, alert), or anchor on the tag's purpose (the adopter rule that motivates the tag — "record instrumentation pipeline changes in AILOG with tag observabilidad" — implies the tag itself is the signal; the content check may be redundant). Happy to test a candidate keyword set against our corpus: current hit rate is 0/19.

Gap 2 — Charter schema: exactly-one originating_* contradicts the framework's own aggregation guidance

The Charter schema rejects originating_ailogs + originating_spec together ({"required":[…]} is not allowed). But the framework's own charter new guidance says day-to-day work inside the Charter produces AILOGs and "the Charter aggregates them via originating_ailogs:". A spec-originated Charter that follows that guidance at close ends up dual-origin — and fails validation.

Empirical: 5 of our 36 charters were dual-origin. In 4 of them the AILOG list was exactly that close-time aggregation (the Charter's own execution AILOG); in 1 the AILOG was the true origin and the spec was area context.

Our local resolution (works, schema-tolerated extra fields): rename the non-origin field — execution_ailogs: for close-time aggregation, context_spec: for area context — keeping exactly one originating_*.

Suggestion: either bless a canonical execution_ailogs: (or closure_ailogs:) field for the documented aggregation use-case, or relax the exactly-one constraint. Right now the schema and the prose pull adopters in opposite directions; N=1 adopter hit it 5 times in 8 weeks.

Gap 3 — CHARTER-FILES-EXIST: no exemption marker for cross-repo / relocated / never-materialized paths in closed Charters

The rule's only exemption is the (new) tag. Closed historical Charters legitimately contain paths that will never exist in the adopter repo:

  • Cross-repo: our CHARTER-01 (the format-v4 proposal, executed against this repo, straymark) declares 12 paths like dist/.straymark/templates/charter-template.md — correct in context, flagged forever in sentinel. The Charter even carries an explicit cross-repo note; the validator can't see it.
  • Relocated / never-materialized: 4 paths across 4 Charters where the implementation landed elsewhere (e.g. a planned interfaces/<module>.go that shipped under a different filename) — already documented in ## Closing notes per format v4, flagged anyway.
  • Placeholder paths: 3 cases of AILOG-YYYY-MM-NNN-… template placeholders never substituted at close. These WERE real doc bugs — the rule earned its keep here.

Our workaround for the first two classes: de-backtick the paths (italics) so the parser — which only registers backtick tokens — skips them, plus a human-readable annotation. It works but it's parser-shaped editing of historical documents, which is exactly what an exemption marker should prevent.

Suggestion: support (external) / (removed) / (relocated: <path>) tags alongside (new) (the NEW_MARKERS machinery in charter_files.rs generalizes naturally), and/or downgrade the rule to info for status: closed Charters — a closed Charter's table is a historical record, not a forward declaration.

Minor note — status-vocabulary drift in AILOGs (META-003)

Over 8 weeks, agents authoring AILOGs invented 6 non-canonical status values (complete, in-progress, done, closed, final, completed) across 28 of 93 docs, while 56 used canonical accepted. The fix was mechanical (28 × normalize → accepted), but the drift rate (~30%) suggests the canonical vocabulary isn't salient at authoring time. Cheap mitigations: META-003's hint could suggest the nearest canonical value ("did you mean accepted?"), and/or the AILOG template could enumerate the vocabulary inline next to the status: field.

Summary

Gap Class Local cost absorbed Ask
OBS-001 keyword set False-positive noise (19/19) Accepted as known noise Widen keywords or trust the tag
Exactly-one originating_* Schema vs prose contradiction (N=5) Semantic field renames Bless execution_ailogs or relax
CHARTER-FILES-EXIST exemptions Historical-record noise (16/19; 3 were real bugs) Italicize workaround (external)/(removed) markers or info-level on closed
META-003 drift Authoring UX (28/93 docs) Mechanical normalize Nearest-canonical hint

As with #214: adopter N=1, gate currency rather than gate triggers — except Gap 2, which is an internal contradiction independent of adopter count.


🤖 Issue body co-authored with Claude Code (Opus 4.8) during the housekeeping session itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions