Repository navigation
docs: additional alignment - #167
Open
Spelkington wants to merge 15 commits into
Open
Spelkington wants to merge 15 commits into
Spelkington wants to merge 15 commits into
Conversation
Five gates that make epic #154's conventions enforceable instead of aspirational. Each fails with a message naming the offending file and the corrective action. - _test:context-file-guard no CONTEXT.md / CONTEXT-MAP.md anywhere. A test rather than a prose rule because four VENDORED skills under .agents/skills/ actively instruct agents to create one and will keep saying so through every upstream update; docs/agents/domain.md only helps if the agent read it, and domain-modeling's instruction fires mid-task. - _test:wikilink-terms every [[Term]] resolves to a glossary entry in some context's CONTRIBUTING.md, and a bare wikilink fails where the term has role-parenthetical variants. Closes a real hole: skill-links.mjs parses standard Markdown links only, so nothing resolved wikilinks before this. - _test:adr-citations every ADR-NNNN names a real ADR, and every link into an ADR directory resolves on disk. This is what makes #157's renumbering safe: the 61 bare-text citations in src/**/*.cs are comments, not Markdown links, so the link linter cannot see them. - _test:context-map-freshness the context map in root CONTRIBUTING.md matches a fresh derivation. Generated by scripts/generate-context-map.mjs, same generate-then-gate pattern as skill-index-freshness (ADR-0025). - _test:adr-frontmatter an ADR declaring the contexts/exemplars/status contract honors it. Migration-tolerant: an ADR counts as migrated once it declares contexts or exemplars, so this lands before #157 without failing the 27 unmigrated ADRs and tightens automatically as each is migrated. scripts/_test/_domain.mjs holds the shared definitions of context, glossary term and ADR, so a convention change is one edit rather than four. Two gates are RED against the current tree, by design (#158: "tests 2 and 3 are expected to fail; the fixes live in #160 and #157"): wikilink-terms 3 dangling links (the 2 known, plus [[Tool]] in src/tools/flowthru-vscode/README.md) adr-citations 19 links into .claude/docs/adr/, a directory that has never existed Refs #158
Closes the four actionable defects from the context/ADR audit. Turns the two meta-test gates that #158 landed red back to green. 1. Skill shard glossary entry named src/extensions/<Ext>/SKILL.md; every actual shard is at <Ext>/skill/SKILL.md. Corrected, and the rationale for the subdirectory recorded: `npx skills add` copies the whole directory containing a SKILL.md, so a shard in the package root would drag .cs/.csproj into a user's skills directory. 2. The Anchor entry cited [ADR-0009] with a path naming 0011, into a directory that never existed. Now a directory pointer. 3. Three dangling wikilinks, not two: [[TestCapabilities.Docker|…]] and [[TestCapabilities.AwsS3|…]] pointed at code identifiers rather than glossary terms, and [[Tool]] in flowthru-vscode/README.md named a term that does not exist (the glossary defines "Tool Developer"). The first is now a plain code reference, the second routes through [[Test capability gate]], the third is prose. 4. Every reference into .claude/docs/adr/ — 19 link instances across 8 files, matching the inventory table in #160 (the "23" in its prose overcounts; the table itself sums to 19). Not a path rewrite: per #154, reader-facing docs and package READMEs LOSE their specific ADR references, CONTRIBUTING.md files keep only a pointer to the ADR directory, and only code comments may cite an ADR by number. Bare-text citations outside code comments are cleared on the same rule; generated docfx output keeps its citations, which #154 permits because it derives from code comments. Defect 5 (Wide vs narrow transform defined twice) is left to #156 as specified. ADR-to-ADR links under docs/adr/ are left to #157. Refs #160
…ontmatter
Relocates, renumbers and backfills frontmatter across the ADR set, and makes
every citation carry a resolvable path.
## Layout
docs/adr/ 12 process, glossary, multi-context
src/core/docs/adr/ 10 renumbered 0001-0010
src/tools/docs/adr/ 2
.../Flowthru.Extensions.Python/docs/adr/ 2
.../Flowthru.Extensions.Google.Sheets/adr/ 1
Python and Google.Sheets are minted as contexts to hold their own ADRs — the
forcing function working as intended ("each package is its own context, created
lazily"). Both carry a real glossary, not a stub.
## Two classification corrections
ADR-0020 STAYS at root. #157 asked to verify its single-context (AWS.S3) label
before moving: verification fails it. src/core/.../SecretText.cs enforces 0020's
"a secret never enters the catalog or the DAG" invariant in Core's own type, so
Core applies it directly rather than conforming. Two contexts ⇒ root. This also
spares its 5 inbound links, the highest in the set.
ADR-0017 goes to root, not an AWS context: the Flowthru.Harness.AWS.Lambda
package it describes does not exist. It is a scope decision ("a harness, not an
orchestrator"), which is repo-wide.
## `proposed` added to the status vocabulary
#154 specifies accepted/superseded/rejected. The exemplars rule immediately
surfaced three ADRs that decide something nothing implements — the diagnostic
anchor contract (no analyzer carries anchor metadata), the Inspector RPC surface
(src/tools contains no .NET project at all), and the Lambda harness (no package).
That is exactly the "asserted but not practised" case the rule exists to expose,
so it is recorded rather than papered over. `proposed` is exempt from the
non-empty-exemplars requirement, which is what lets `accepted` keep its teeth.
## Citations
87 bare ADR-NNNN citations — not 61; the original count missed tests/** — are now
markdown links carrying the full root-anchored path. Per-directory renumbering
makes a bare number ambiguous across five ADR directories, and a docstring is
built into reference markdown, so a citation must resolve as a link. Verified
end-to-end: docfx passes the markdown through verbatim, and docs/reference/src/
is regenerated here.
Also fixes a latent bug this exposed: ingest-docs.mjs treated /docs/adr/ as
site-internal, but ADRs are deliberately never ingested, so every such link
minted a page that cannot exist. They now resolve as repo source (GitHub).
All ADR-to-ADR links are root-anchored; no relative or upward forms remain.
Refs #157
Fixes the uphill vocabulary flow. src/extensions/CONTRIBUTING.md had become the repo's de-facto shared glossary: 11 terms of which only 3 were extensions-owned. The sharpest symptom was src/core citing API Surface (3x) and Error Surface (2x) — its own two stated primary responsibilities — from one tier down. Root gains a ## Glossary with 7 terms: Context (new), Shippable package, API Surface, Error Surface, Design-time error, Pre-flight error, Runtime error (phase) Closed sum moves to src/core, where it belongs — it is a Core implementation pattern, and Core's own audience-scope line had been pointing downward at it. src/extensions keeps exactly what it owns: Extension Developer, Extension surface, Skill shard (plus its half of the split transform entry). ## Role parentheticals Two terms genuinely mean different things to different readers, so per #154 they are disambiguated in the entry NAME rather than by reciprocal prose: Runtime error (phase) the third error phase — when a failure is caught Runtime error (Core Developer) the RuntimeError closed sum — a value, never thrown Wide vs narrow transform (Flow Developer) classified by what the author must see Wide vs narrow transform (Extension Developer) classified by streamability The second pair resolves a real defect: the two entries gave conflicting defining axes and asymmetric _Avoid_ lists with no cross-reference, so reading one file gave you a different rule than reading the other. They now state the same split from each audience's side and say so explicitly. This also puts #158's ambiguity check to work for the first time — until now no role-parenthetical term existed, so the branch was logically sound but unexercised. A bare [[Runtime error]] or [[Wide vs narrow transform]] is now a test failure naming both full forms. Context is defined against Shippable package as #156 asks, but honestly: contexts are minted lazily, so a shippable package *becomes* one when it accrues its own words, and many contexts (examples, tests/*, docs) ship nothing at all. Refs #156
src/website had no CONTRIBUTING.md despite clearly clearing the bar ADR-0007 set
when it minted src/tools — structurally different artifacts: Node/Astro/
TypeScript, an application rather than a .NET library, "private": true, not in
Flowthru.slnx, deployed by its own workflow.
It carried ~15 load-bearing terms that survived only as comments inside
project.json and two .mjs files, where nothing could reference them and no
contributor would find them. They are now a glossary with _Avoid_ lines:
Ingest / Passthrough vs. synthesize why synthesis is confined to reference/
Link interceptor inside docs/ vs escapes docs/, and the
docs/adr/ exception
Frontmatter contract enforced twice, deliberately
Source-path mapping errors name the file you would edit
Source-inputs-not-ingested-outputs nx hashes inputs before ingest writes,
so listing the copy memoizes stale builds
Build honesty Starlight's link validator is a build
hook, so an incremental build skips
pages AND their link checks
Scope-primary IA decided, not yet implemented
Review provenance absent reads as draft, never reviewed
Also fixes the dead pointer the audit found: README sent readers to
INTEGRATION.md for "the full handoff guide" — nx wiring, the C#-to-Markdown
generator contract, and Pages deployment — and that file has never existed. Those
three things are now documented where they belong.
Root goes from five roles to six. The generated context map picks up website,
Python and Google.Sheets automatically: 8 contexts at the start of this epic,
11 now, growing toward ~22 as extension packages mint themselves.
Refs #159
…matter Records the decisions the rest of this epic implements. Supersedes ADR-0004 and extends ADR-0007; ADR-0004 gains a superseded-by pointer and drops to superseded. Dogfoods its own contract: contexts, exemplars, status frontmatter, with the seven files that demonstrate it in practice as exemplars. Two things the implementation forced into the record, neither in #154's original statement: - `proposed` joins the status vocabulary. Backfilling frontmatter surfaced three ADRs deciding something nothing implements — the diagnostic anchor contract, the Inspector RPC surface, the Lambda harness. Forcing them to `accepted` meant fabricating exemplars; leaving them unmigrated exempted them from the contract. `proposed` is exempt from non-empty exemplars, which is what lets `accepted` keep its teeth. - Per-directory numbering makes a bare ADR-NNNN meaningless (five directories now each start at 0001), so every citation carries the full root-anchored path. The ADR states this as the transitive requirement it is: markdown must not have dead links, C# docstrings become markdown reference docs, therefore docstrings must not have dead links. Filed as 0026 would have reused a number the old global ADR-0026 held until this epic moved it, so this takes 0028 to keep git history unambiguous. Refs #155
Code review caught a double-application bug in the migration script. It rewrote ADR references in three passes: relative links, then bare ADR-NNNN into links, then existing [ADR-NNNN](...) links onto their new numbers. The third pass ran over the second pass's output and re-mapped the NEW number as if it were an old one, so a citation that had been bare in the source silently acquired a valid link to an unrelated ADR. Five citations landed wrong, all internally consistent and all resolving, which is why nothing caught them: src/core/.../0002 2x [ADR-0001] -> glossary-split should be step-logging src/core/.../0009 2x [ADR-0008] -> documentation-honesty should be streaming-reads src/core/.../0009 1x [ADR-0007] -> tools-as-context should be hermetic-preflight Found by re-deriving every citation from the pre-migration tree and diffing against what shipped, not by inspection — the label and the path agreed in every case, so a consistency check finds nothing. The gate was complicit. It asked "does some ADR have this number?", which every bare citation passes by accident now that five directories each start at 0001. That is false confidence in exactly the check that exists to make renumbering safe. A bare ADR-NNNN is now a failure telling the author to carry the full path, which is the rule the epic settled on anyway and the reason docstrings carry paths at all. The hardened gate immediately found 6 more bare citations in files added earlier in this branch — 5 in the new ADR, 1 in src/website/CONTRIBUTING.md, where the fix is a directory pointer rather than a link, since CONTRIBUTING files may reference only that an ADR directory exists.
…ecision Spec review finding. When #160 converted specific ADR citations in CONTRIBUTING files into "an ADR directory exists" pointers, every one was hardcoded to root /docs/adr — correct at the time, wrong the moment #157 relocated those decisions. Eight pointers named a directory that does not contain what they cite: src/core/CONTRIBUTING.md x5 logging, ObservationOnly, conflict, hermetic pre-flight, Anchor -> /src/core/docs/adr src/tools/CONTRIBUTING.md x3 Inspector RPC, trust boundary, snapshot lifecycle -> /src/tools/docs/adr examples/CONTRIBUTING.md x1 step logging -> /src/core/docs/adr The four that legitimately stay at root are left alone: src/tools' "why Tools are a context" and src/website's context-minting bar (both ADR-0007), and src/extensions' documentation-honesty reference (ADR-0008). Invisible to the citation validator because a directory pointer carries no ADR-NNNN for it to scan — the same blind spot that let the mis-targeted links in the previous commit through. Also: adr-citations now masks code spans and fenced blocks before scanning, the rule lint-doc-links.mjs and the ingest interceptor already follow. Documentation about the citation convention has to be able to show an example citation without the gate treating the example as a broken link.
Winds back the `proposed` status. `main` is the canonical state of the repository, so an ADR merged into it should describe something the repository actually does. `proposed` was the wrong answer to a real problem. Backfilling frontmatter surfaced three ADRs deciding things nothing implements, and adding a status for them meant adding an exemption from the non-empty-exemplars rule. Every exemption is a way to assert a decision without practising it — exactly what exemplars exists to prevent. One unimplemented ADR on main under a soft status teaches the next reader that the standard is optional. Moved off the mainline, each to its own adr/<slug> branch so it can merge with its implementation: adr/diagnostic-anchor-contract no analyzer carries anchor metadata adr/inspector-rpc src/tools contains no .NET project at all adr/aws-lambda-harness Flowthru.Harness.AWS.Lambda does not exist main now has 25 ADRs: 23 accepted with resolving exemplars, 2 superseded. The gate has no escape hatch left — `accepted` requires a non-empty exemplar list, and only `superseded` / `rejected` are exempt, both describing exemplars that are gone rather than absent. Numbering gaps left behind (src/core 0004, src/tools 0001, root 0017) are kept, not closed. Renumbering the survivors would invalidate citations that currently resolve — the exact failure the last review caught — and a gap costs nothing. One forward-looking link in the concurrency ADR pointed at the Lambda harness; it now names the concept without citing an ADR that main does not carry.
A bare "'proposed' is not one of accepted / superseded / rejected" tells an author the status is wrong but not what to do. The ADR is usually fine — it is on the wrong branch. Say that instead.
An invalid status already tells the author what to fix; following it with "status 'proposed' requires at least one exemplar" reads as a second, conflicting demand. Check exemplars only once the status is valid.
Two findings from the review, both stale state rather than new defects. ## docs/reference/src/ was gitignored yet 340 files stayed tracked The ignore rule landed without an untrack, so git kept carrying files it was told to ignore — and they drift: regenerating during the ADR migration produced 6 changed files against the committed copy. Nothing needs the committed copy. The chain is complete on its own: site:build -> site:_lint-docs -> site:_ingest-docs -> docs:build -> docs:_build-reference -> docfx. The reference is always regenerated before it is consumed, so a tracked copy can only ever be a stale duplicate of a build artifact. ## _test:capability-matrix-freshness was quarantined on a claim that expired Its note said capability-matrix.cs referenced legacy namespaces that did not survive the FP rewrite. It does not: the generator builds and runs clean, and its output already matches the committed matrix byte for byte — so the target was excluded from the barrel for a reason that had quietly stopped being true. Back in dependsOn, and the note now records what is actually the case. Worth noting docs:_build-capability-matrix already ran this same generator on every docs build, so the quarantine only ever disabled the freshness CHECK, never the generation — the matrix could have drifted with nothing watching. Barrel is 15 subtargets, all green.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.