@timiagama/ecr 0.0.1 → 0.1.0

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.
Files changed (138) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +411 -7
  4. package/dist/bin.d.ts +20 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +26 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/cli/corpus-loader.d.ts +198 -0
  9. package/dist/cli/corpus-loader.d.ts.map +1 -0
  10. package/dist/cli/corpus-loader.js +351 -0
  11. package/dist/cli/corpus-loader.js.map +1 -0
  12. package/dist/cli/corpus-statistics.d.ts +113 -0
  13. package/dist/cli/corpus-statistics.d.ts.map +1 -0
  14. package/dist/cli/corpus-statistics.js +119 -0
  15. package/dist/cli/corpus-statistics.js.map +1 -0
  16. package/dist/cli/diagnostic-reporter.d.ts +103 -0
  17. package/dist/cli/diagnostic-reporter.d.ts.map +1 -0
  18. package/dist/cli/diagnostic-reporter.js +254 -0
  19. package/dist/cli/diagnostic-reporter.js.map +1 -0
  20. package/dist/cli/project-ignore.d.ts +113 -0
  21. package/dist/cli/project-ignore.d.ts.map +1 -0
  22. package/dist/cli/project-ignore.js +199 -0
  23. package/dist/cli/project-ignore.js.map +1 -0
  24. package/dist/cli/safe-text.d.ts +25 -0
  25. package/dist/cli/safe-text.d.ts.map +1 -0
  26. package/dist/cli/safe-text.js +34 -0
  27. package/dist/cli/safe-text.js.map +1 -0
  28. package/dist/cli/supervisor.d.ts +108 -0
  29. package/dist/cli/supervisor.d.ts.map +1 -0
  30. package/dist/cli/supervisor.js +139 -0
  31. package/dist/cli/supervisor.js.map +1 -0
  32. package/dist/cli.d.ts +247 -0
  33. package/dist/cli.d.ts.map +1 -0
  34. package/dist/cli.js +591 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/corpus-validator.d.ts +183 -0
  37. package/dist/corpus-validator.d.ts.map +1 -0
  38. package/dist/corpus-validator.js +479 -0
  39. package/dist/corpus-validator.js.map +1 -0
  40. package/dist/document-identity-rule.d.ts +198 -0
  41. package/dist/document-identity-rule.d.ts.map +1 -0
  42. package/dist/document-identity-rule.js +244 -0
  43. package/dist/document-identity-rule.js.map +1 -0
  44. package/dist/ecr.d.ts +103 -0
  45. package/dist/ecr.d.ts.map +1 -0
  46. package/dist/ecr.js +216 -0
  47. package/dist/ecr.js.map +1 -0
  48. package/dist/glob-pattern.d.ts +94 -0
  49. package/dist/glob-pattern.d.ts.map +1 -0
  50. package/dist/glob-pattern.js +188 -0
  51. package/dist/glob-pattern.js.map +1 -0
  52. package/dist/heading-source-form.d.ts +77 -0
  53. package/dist/heading-source-form.d.ts.map +1 -0
  54. package/dist/heading-source-form.js +129 -0
  55. package/dist/heading-source-form.js.map +1 -0
  56. package/dist/identifier-grammar.d.ts +212 -0
  57. package/dist/identifier-grammar.d.ts.map +1 -0
  58. package/dist/identifier-grammar.js +273 -0
  59. package/dist/identifier-grammar.js.map +1 -0
  60. package/dist/index.d.ts +19 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +11 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/inline-reference-rule.d.ts +557 -0
  65. package/dist/inline-reference-rule.d.ts.map +1 -0
  66. package/dist/inline-reference-rule.js +802 -0
  67. package/dist/inline-reference-rule.js.map +1 -0
  68. package/dist/meta-documents.d.ts +91 -0
  69. package/dist/meta-documents.d.ts.map +1 -0
  70. package/dist/meta-documents.js +133 -0
  71. package/dist/meta-documents.js.map +1 -0
  72. package/dist/per-document-visitor.d.ts +510 -0
  73. package/dist/per-document-visitor.d.ts.map +1 -0
  74. package/dist/per-document-visitor.js +1032 -0
  75. package/dist/per-document-visitor.js.map +1 -0
  76. package/dist/references-section-rule.d.ts +482 -0
  77. package/dist/references-section-rule.d.ts.map +1 -0
  78. package/dist/references-section-rule.js +777 -0
  79. package/dist/references-section-rule.js.map +1 -0
  80. package/dist/section-hierarchy-rule.d.ts +299 -0
  81. package/dist/section-hierarchy-rule.d.ts.map +1 -0
  82. package/dist/section-hierarchy-rule.js +482 -0
  83. package/dist/section-hierarchy-rule.js.map +1 -0
  84. package/dist/source-alignment.d.ts +41 -0
  85. package/dist/source-alignment.d.ts.map +1 -0
  86. package/dist/source-alignment.js +166 -0
  87. package/dist/source-alignment.js.map +1 -0
  88. package/dist/source-lines.d.ts +69 -0
  89. package/dist/source-lines.d.ts.map +1 -0
  90. package/dist/source-lines.js +104 -0
  91. package/dist/source-lines.js.map +1 -0
  92. package/dist/spec-version.d.ts +19 -0
  93. package/dist/spec-version.d.ts.map +1 -0
  94. package/dist/spec-version.js +19 -0
  95. package/dist/spec-version.js.map +1 -0
  96. package/dist/types.d.ts +219 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +11 -0
  99. package/dist/types.js.map +1 -0
  100. package/examples/docs/0. Orientation/0.0 - System Overview.md +34 -0
  101. package/examples/docs/0. Orientation/0.0.1 - Glossary.md +21 -0
  102. package/examples/docs/0. Orientation/0.0.2 - Quality Gates.md +22 -0
  103. package/examples/docs/3. Ingestion/3.1 - Ingestion - Validation Rules.md +33 -0
  104. package/examples/docs/4. Payments/4.10 - Settlement.md +22 -0
  105. package/examples/docs/4. Payments/4.2 - Payment Processing Contract.md +33 -0
  106. package/examples/docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md +38 -0
  107. package/examples/docs/8. Orchestration/8.1.3 - Retry Policy.md +17 -0
  108. package/examples/docs/8. Orchestration/8.10 - Dead Letter Queue.md +20 -0
  109. package/examples/docs/README.md +7 -0
  110. package/package.json +65 -7
  111. package/protocol/navigation-protocol.md +223 -0
  112. package/spec/v2/1 - ECR - Structural Specification.md +1467 -0
  113. package/spec/v2/2 - ECR - User Guide.md +845 -0
  114. package/spec/v2/3 - Design Rationale - The Section Separator.md +243 -0
  115. package/src/bin.ts +30 -0
  116. package/src/cli/corpus-loader.ts +482 -0
  117. package/src/cli/corpus-statistics.ts +196 -0
  118. package/src/cli/diagnostic-reporter.ts +344 -0
  119. package/src/cli/project-ignore.ts +238 -0
  120. package/src/cli/safe-text.ts +39 -0
  121. package/src/cli/supervisor.ts +204 -0
  122. package/src/cli.ts +836 -0
  123. package/src/corpus-validator.ts +642 -0
  124. package/src/document-identity-rule.ts +422 -0
  125. package/src/ecr.ts +298 -0
  126. package/src/glob-pattern.ts +242 -0
  127. package/src/heading-source-form.ts +173 -0
  128. package/src/identifier-grammar.ts +380 -0
  129. package/src/index.ts +78 -0
  130. package/src/inline-reference-rule.ts +1235 -0
  131. package/src/meta-documents.ts +159 -0
  132. package/src/per-document-visitor.ts +1528 -0
  133. package/src/references-section-rule.ts +1182 -0
  134. package/src/section-hierarchy-rule.ts +705 -0
  135. package/src/source-alignment.ts +209 -0
  136. package/src/source-lines.ts +123 -0
  137. package/src/spec-version.ts +19 -0
  138. package/src/types.ts +267 -0
@@ -0,0 +1,34 @@
1
+ # 0.0 - System Overview
2
+
3
+ A payments platform that ingests merchant settlement files, validates them,
4
+ and processes the resulting payment instructions.
5
+
6
+ ## 0.0#1 - Purpose
7
+
8
+ This document is the orientation map. It carries no normative rules of its own;
9
+ each domain is governed by its own authority document.
10
+
11
+ ## 0.0#2 - Mental Model
12
+
13
+ ### 0.0#2.1 - The Happy Path
14
+
15
+ A settlement file arrives, is validated per 3.1, and produces payment
16
+ instructions executed per 4.2.
17
+
18
+ ### 0.0#2.2 - Failure Handling
19
+
20
+ Every stage runs under the orchestration contract, so retry semantics are
21
+ uniform across the platform — see 8.1#3.
22
+
23
+ ## 0.0#3 - Where To Start
24
+
25
+ New engineers should read 0.0.1 before anything else. Build and review
26
+ expectations are defined in 0.0.2.
27
+
28
+ ## References
29
+
30
+ - 0.0.1 - Glossary (dependency - defines the vocabulary used throughout this overview)
31
+ - 0.0.2 - Quality Gates (dependency - the build and review expectations referenced here)
32
+ - 3.1 - Ingestion - Validation Rules (dependency - the validation stage described in this overview)
33
+ - 4.2 - Payment Processing Contract (dependency - the execution stage described in this overview)
34
+ - 8.1 - Workflow Orchestration Contract (authority - governs the runtime behaviour of every stage)
@@ -0,0 +1,21 @@
1
+ # 0.0.1 - Glossary
2
+
3
+ Vocabulary shared across the corpus. Terms defined here are used with this
4
+ meaning everywhere; a document that needs a narrower meaning must say so.
5
+
6
+ ## 0.0.1#1 - Settlement File
7
+
8
+ A merchant-submitted batch of transactions awaiting reconciliation.
9
+
10
+ ## 0.0.1#2 - Payment Instruction
11
+
12
+ A single validated, executable transfer derived from a settlement file.
13
+
14
+ ## 0.0.1#3 - Idempotency Key
15
+
16
+ The value that makes retrying a payment instruction safe. Its derivation is
17
+ defined per 4.2#1.1 and must not be reimplemented elsewhere.
18
+
19
+ ## References
20
+
21
+ - 4.2 - Payment Processing Contract (contract - defines idempotency key derivation referenced here)
@@ -0,0 +1,22 @@
1
+ # 0.0.2 – Quality Gates
2
+
3
+ Build and review expectations. This document uses an en dash in its H1 to
4
+ demonstrate that the separator variant carries no structural meaning.
5
+
6
+ ## 0.0.2#1 - Purpose
7
+
8
+ To state what "done" means, so that review is a check rather than a negotiation.
9
+
10
+ ## 0.0.2#2 — Test Coverage
11
+
12
+ Every behavioural change ships with a test in the standing suite. A throwaway
13
+ script is not coverage.
14
+
15
+ ## 0.0.2#3 - Review Order
16
+
17
+ Implementation and review happen in separate sessions. See 0.0#3 for where this
18
+ sits in onboarding.
19
+
20
+ ## References
21
+
22
+ - 0.0 - System Overview (dependency - the orientation map that points here)
@@ -0,0 +1,33 @@
1
+ # 3.1 - Ingestion - Validation Rules
2
+
3
+ Authoritative rules for accepting or rejecting a settlement file. A file that
4
+ fails any rule here never reaches payment processing.
5
+
6
+ ## 3.1#1 - Structural Validation
7
+
8
+ ### 3.1#1.1 - Required Columns
9
+
10
+ A settlement file must carry merchant identifier, amount, currency and
11
+ transaction reference. Missing columns reject the whole file, not the row.
12
+
13
+ ### 3.1#1.2 - Encoding
14
+
15
+ Files are UTF-8. A file that fails to decode is rejected without partial
16
+ processing.
17
+
18
+ ## 3.1#2 - Semantic Validation
19
+
20
+ Amounts must be positive integers in minor units. Currency must be ISO 4217.
21
+
22
+ ## 3.1#3 - Rejection Reporting
23
+
24
+ This stage is invoked under the orchestration contract, per 8.1.
25
+
26
+ A rejected file produces one report naming every failed rule. Rejection is not
27
+ retried automatically — retry semantics apply to transient failures only,
28
+ per 8.1#3.
29
+
30
+ ## References
31
+
32
+ - 0.0.1 - Glossary (dependency - defines settlement file and payment instruction)
33
+ - 8.1 - Workflow Orchestration Contract (constraint - retry semantics that bound this stage)
@@ -0,0 +1,22 @@
1
+ # 4.10 — Settlement
2
+
3
+ Reconciliation of executed payment instructions against merchant expectations.
4
+ This document's DocID shares a prefix with 4.1 in text but is a distinct
5
+ document; identifier matching is by segment, not by string prefix.
6
+
7
+ ## 4.10#1 - Reconciliation Window
8
+
9
+ Settlement runs daily. An instruction executed after the cut-off settles in the
10
+ next window.
11
+
12
+ ## 4.10#2 - Discrepancies
13
+
14
+ Settlement runs as an orchestrated stage; see 8.1 for invocation and retry.
15
+
16
+ A discrepancy halts settlement for that merchant only. Orchestration-level
17
+ retry does not apply — see 8.1#3.2.
18
+
19
+ ## References
20
+
21
+ - 4.2 - Payment Processing Contract (dependency - the upstream stage that produces settled instructions)
22
+ - 8.1 - Workflow Orchestration Contract (constraint - bounds the retry behaviour excluded here)
@@ -0,0 +1,33 @@
1
+ # 4.2 - Payment Processing Contract
2
+
3
+ The contract every payment executor must satisfy. This document defines
4
+ obligations, not implementation.
5
+
6
+ ## 4.2#1 - Idempotency
7
+
8
+ ### 4.2#1.1 - Key Derivation
9
+
10
+ The idempotency key is the SHA-256 of merchant identifier, transaction
11
+ reference and amount in minor units, joined by U+001F. This derivation is
12
+ normative; see 0.0.1#3 for the term itself.
13
+
14
+ ### 4.2#1.2 - Replay
15
+
16
+ A repeated instruction carrying a known key returns the original result and
17
+ performs no new transfer.
18
+
19
+ ## 4.2#2 - Ordering
20
+
21
+ Instructions within a settlement file are independent and may execute in any
22
+ order. Cross-file ordering is not guaranteed.
23
+
24
+ ## 4.2#3 - Settlement Handoff
25
+
26
+ Completed instructions are handed to settlement per 4.10.
27
+
28
+ ## References
29
+
30
+ - 0.0.1 - Glossary (dependency - defines the idempotency key term this contract derives)
31
+ - 3.1 - Ingestion - Validation Rules (authority - only validated instructions reach this contract)
32
+ - 4.10 - Settlement (dependency - the downstream stage this contract hands off to)
33
+ - 8.1 - Workflow Orchestration Contract (authority - governs execution and retry of this contract)
@@ -0,0 +1,38 @@
1
+ # 8.1 - Workflow Orchestration Contract
2
+
3
+ Governs how every stage in the platform runs: invocation, failure
4
+ classification and retry. This document is an authority for the runtime
5
+ behaviour of the stages it governs; it does not define what those stages do.
6
+
7
+ ## 8.1#1 - Stage Invocation
8
+
9
+ A stage is invoked with a single immutable input and returns a single result.
10
+ Stages do not share mutable state.
11
+
12
+ ## 8.1#2 - Failure Classification
13
+
14
+ ### 8.1#2.1 - Transient Failures
15
+
16
+ Network timeouts, lock contention and rate limiting. Eligible for retry.
17
+
18
+ ### 8.1#2.2 - Permanent Failures
19
+
20
+ Validation rejections and contract violations. Never retried; see 3.1#3.
21
+
22
+ ## 8.1#3 - Retry Semantics
23
+
24
+ ### 8.1#3.1 - Backoff
25
+
26
+ Exponential with full jitter, base 200ms, ceiling 30s.
27
+
28
+ ### 8.1#3.2 - Bounds
29
+
30
+ At most five attempts. A stage that exhausts its attempts fails permanently and
31
+ is reported, not re-queued. The concrete policy is defined per 8.1.3, and the
32
+ exhausted invocation is routed per 8.10.
33
+
34
+ ## References
35
+
36
+ - 3.1 - Ingestion - Validation Rules (dependency - the rejection behaviour classified as permanent here)
37
+ - 8.1.3 - Retry Policy (contract - the concrete policy values this contract delegates to)
38
+ - 8.10 - Dead Letter Queue (dependency - where exhausted invocations are routed)
@@ -0,0 +1,17 @@
1
+ # 8.1.3 - Retry Policy
2
+
3
+ Concrete retry values. This document's DocID extends 8.1, and its sections are
4
+ addressed as 8.1.3#N — distinct from 8.1's own sections, which are 8.1#N.
5
+
6
+ ## 8.1.3#1 - Bounds
7
+
8
+ Maximum five attempts per stage invocation, as required per 8.1#3.2.
9
+
10
+ ## 8.1.3#2 - Backoff Parameters
11
+
12
+ Base 200ms, ceiling 30s, full jitter. Values are configuration, not contract;
13
+ changing them does not change 8.1.
14
+
15
+ ## References
16
+
17
+ - 8.1 - Workflow Orchestration Contract (authority - defines the retry semantics these values implement)
@@ -0,0 +1,20 @@
1
+ # 8.10 - Dead Letter Queue
2
+
3
+ Where permanently failed stage invocations go. Its DocID begins with the same
4
+ characters as 8.1 but is a different document: identifiers compare by segment,
5
+ never by string prefix.
6
+
7
+ ## 8.10#1 - Entry Conditions
8
+
9
+ A stage invocation enters the queue when it fails permanently, or when it
10
+ exhausts its retry attempts as bounded per 8.1#3.2.
11
+
12
+ ## 8.10#2 - Replay
13
+
14
+ Replay is manual and produces a fresh idempotency key only when the original
15
+ instruction has been superseded — see 4.2#1.
16
+
17
+ ## References
18
+
19
+ - 4.2 - Payment Processing Contract (dependency - idempotency behaviour on replay)
20
+ - 8.1 - Workflow Orchestration Contract (authority - defines the failure classification that routes here)
@@ -0,0 +1,7 @@
1
+ # Example Corpus
2
+
3
+ A small ECR-compliant corpus used as a worked example and as the fixture for
4
+ this repository's navigation-recipe tests.
5
+
6
+ This file is a meta-document: it carries no DocID and sits outside the reference
7
+ graph. `ecr lint` excludes it by default.
package/package.json CHANGED
@@ -1,18 +1,76 @@
1
1
  {
2
2
  "name": "@timiagama/ecr",
3
- "version": "0.0.1",
4
- "description": "Placeholder. Explicit Constraint Referencing (ECR): a Markdown convention and linter that turns cross-references in architecture documents into a graph agents can navigate with grep. The first release is 0.1.0.",
5
- "license": "Apache-2.0",
6
- "author": "Timi Agama",
3
+ "version": "0.1.0",
4
+ "description": "Explicit Constraint Referencing (ECR): a Markdown convention that helps reduce coding-agent errors by turning cross-references in architecture docs into a graph that agents can navigate with grep. Agents gain IDE-like \"Go to Definition\" and \"Find all references\" across large document corpora, reducing missed constraints and context-window bloat.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "ecr": "./dist/bin.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src",
14
+ "spec",
15
+ "protocol",
16
+ "examples",
17
+ "README.md",
18
+ "LICENSE",
19
+ "NOTICE"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22"
23
+ },
24
+ "keywords": [
25
+ "markdown",
26
+ "documentation",
27
+ "architecture",
28
+ "coding-agent",
29
+ "ai-agent",
30
+ "llm",
31
+ "context-engineering",
32
+ "constraint",
33
+ "linter",
34
+ "ecr"
35
+ ],
7
36
  "repository": {
8
37
  "type": "git",
9
38
  "url": "git+https://github.com/timiagama/ecr.git"
10
39
  },
11
40
  "homepage": "https://github.com/timiagama/ecr#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/timiagama/ecr/issues"
43
+ },
44
+ "author": "Timi Agama",
45
+ "license": "Apache-2.0",
12
46
  "publishConfig": {
13
47
  "access": "public"
14
48
  },
15
- "files": [
16
- "README.md"
17
- ]
49
+ "scripts": {
50
+ "build": "npm run clean && npm run generate:protocol && tsc",
51
+ "generate:protocol": "node scripts/generate-navigation-protocol.mjs",
52
+ "test": "vitest run",
53
+ "lint": "eslint src/ tests/",
54
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.eslint.json",
55
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
56
+ "prepublishOnly": "npm run verify",
57
+ "verify": "npm run typecheck && npm run lint && npm test && npm run build && node dist/bin.js lint spec/v2 && node dist/bin.js lint docs/engineering && node dist/bin.js lint --example"
58
+ },
59
+ "dependencies": {
60
+ "decode-named-character-reference": "^1.3.0",
61
+ "micromark-util-decode-numeric-character-reference": "^2.0.2",
62
+ "remark-parse": "^11.0.0",
63
+ "unified": "^11.0.5"
64
+ },
65
+ "devDependencies": {
66
+ "@eslint/js": "^9.39.2",
67
+ "@types/node": "^22.10.0",
68
+ "@vscode/ripgrep": "^1.18.0",
69
+ "eslint": "^9.39.2",
70
+ "eslint-plugin-jsdoc": "^62.5.5",
71
+ "eslint-plugin-tsdoc": "^0.5.0",
72
+ "typescript": "~6.0.3",
73
+ "typescript-eslint": "^8.55.0",
74
+ "vitest": "^4.0.18"
75
+ }
18
76
  }
@@ -0,0 +1,223 @@
1
+ # ECR Navigation Protocol for Coding Agents
2
+
3
+ You are grounding an implementation task against a documentation corpus written
4
+ with **Explicit Constraint Referencing (ECR)**. **Do not load the corpus
5
+ wholesale.** Every architectural document carries a stable numeric identity (a
6
+ *DocID*), every sub-heading carries a *SectionID*, and every document declares its
7
+ external references, each with a type. That structure lets you walk to exactly
8
+ the sections a task depends on, and stop.
9
+
10
+ Read this once when a task starts, then navigate on demand. Keep the corpus out
11
+ of your context except the sections you are actively using.
12
+
13
+ ## 1 - What the structure gives you
14
+
15
+ **DocID.** The number in a document's H1:
16
+
17
+ ```
18
+ # 4.2 - Payment Processing Contract
19
+ ```
20
+
21
+ - DocIDs are globally unique and stable. The DocID **is** the document's
22
+ identity — not its title, not its path.
23
+ - Many corpora also start each filename with its DocID and group documents
24
+ into folders by first segment (`4. Payments/4.2 - Payment Processing
25
+ Contract.md`). Where yours does, you can jump to a directory from the number
26
+ alone — but ECR does not require it, so when the path and the H1 disagree,
27
+ the H1 is authoritative.
28
+ - DocIDs may be any depth, and one DocID may be a prefix of another. `8.1` and
29
+ `8.1.3` may both be documents, and `8.10` is a third, unrelated to either.
30
+ **Compare identifiers by segment, never by string prefix.**
31
+
32
+ **SectionID.** A DocID, then `#`, then a dot-separated section path:
33
+
34
+ ```
35
+ ## 8.1#3 - Retry Semantics
36
+ ### 8.1#3.1 - Backoff
37
+ ```
38
+
39
+ `8.1#3.1` is document `8.1`, section 3, sub-section 1. The `#` is what makes the
40
+ identifier unambiguous: everything before it is the document, everything after
41
+ it is the path within that document. A heading at depth *d* carries *d − 1*
42
+ section-path segments.
43
+
44
+ **SectionID stability.** SectionIDs are identities, not sequence numbers. They need
45
+ not be contiguous or appear in numeric order, so do not renumber existing sections
46
+ merely to remove gaps or reflect document order. Existing SectionIDs remain stable
47
+ when unrelated sections are inserted or reordered. Nested SectionIDs encode their
48
+ parent path, however: moving a subsection under a different parent, or promoting it
49
+ to another heading level, changes its identity and requires affected references to
50
+ be updated. Prefer a top-level SectionID for a consumer reference when it expresses
51
+ the required constraint precisely enough; use a subsection address when the narrower
52
+ rule is what the consumer actually depends on.
53
+
54
+ **References.** Every ECR document carries a `## References` section
55
+ declaring its typed, document-level references. Read it before acting on the
56
+ document. References entries cite documents, never sections.
57
+
58
+ **Inline references.** `see X` and `per X` point into another document, either
59
+ at a whole document (`see 8.1`) or at a precise section (`per 8.1#3.2`). They
60
+ may be capitalised at the start of a sentence, so match `[Ss]ee` and `[Pp]er`.
61
+
62
+ **Meta-documents.** Repository-level instruction and orientation files such as
63
+ `README`, `CLAUDE.md`, `AGENTS.md`, contributing guides and changelogs may sit
64
+ outside the reference graph and therefore carry no DocID. Do not assume every
65
+ Markdown file in or near a corpus is an ECR document.
66
+
67
+ ## 2 - How to find things
68
+
69
+ Patterns are ripgrep. Escape the dots in an identifier. If `rg` is not
70
+ installed, GNU grep takes the same patterns: use `grep -rnE` for `rg --no-ignore -n`,
71
+ `grep -rlE` for `rg --no-ignore -l`, and `grep -rnP` for `rg --no-ignore -P -n`.
72
+
73
+ `--no-ignore` makes ripgrep also search files listed in `.gitignore`, `.ignore`
74
+ and `.rgignore`, which the CLI validates. Without it, a valid document can be
75
+ invisible to your search.
76
+
77
+ These searches do not follow symbolic links or junctions inside the corpus, and
78
+ the `ecr` CLI does not validate what is behind them. A corpus directory named on
79
+ the command line is followed even when it is itself a link, by the searches and
80
+ the CLI alike.
81
+
82
+ **Open the document for a DocID.**
83
+
84
+ ```bash
85
+ rg --no-ignore -l "^# 8\.1[^0-9.#]" docs # the H1 for 8.1, not 8.10 or 8.1.3
86
+ ```
87
+
88
+ **Resolve a SectionID** — jump straight to the heading:
89
+
90
+ ```bash
91
+ rg --no-ignore -n "^#+ 8\.1#3\.1([^0-9]|$)" docs
92
+ ```
93
+
94
+ **Read a document's declared references (forward edges):**
95
+
96
+ ```bash
97
+ rg -n -A 40 "^## References" "docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md"
98
+ ```
99
+
100
+ **Find who relies on a document, or on one specific section (reverse edges).**
101
+ Nothing precomputes this — grep the citations. Run this *before editing a
102
+ section* to see exactly who leans on that spot.
103
+
104
+ | Question | Pattern |
105
+ |---|---|
106
+ | Who references document `8.1`? | `rg --no-ignore -n "(\b\|_)([Ss]ee\|[Pp]er) 8\.1(\.[^0-9A-Za-z.#]\|\.$\|[^0-9A-Za-z.#]\|$)" docs` |
107
+ | Who references any section of `8.1`? | `rg --no-ignore -n "(\b\|_)([Ss]ee\|[Pp]er) 8\.1#" docs` |
108
+ | Who references section `8.1#3` or below? | `rg --no-ignore -n "(\b\|_)([Ss]ee\|[Pp]er) 8\.1#3([^0-9A-Za-z#]\|$)" docs` |
109
+ | Either the document or any section? | `rg --no-ignore -n "(\b\|_)([Ss]ee\|[Pp]er) 8\.1(#[0-9.]*\|\.[^0-9A-Za-z.#]\|\.$\|[^0-9A-Za-z.#]\|$)" docs` |
110
+ | Every section-precise reference in the corpus | `rg --no-ignore -n "(\b\|_)([Ss]ee\|[Pp]er) [0-9.]+#" docs` |
111
+ | References-section entries citing `8.1` | `rg --no-ignore -n "^\s*([-*+]|[0-9]+[.)])\s*\[?8\.1[^0-9.#]" docs` |
112
+
113
+ These patterns bound a citation explicitly, because `\b` alone fails at both
114
+ ends. It cannot terminate a dotted identifier: `.` and `#` are both non-word
115
+ characters, so `8\.1\b` matches inside `8.1.3`, `8.1#3` and `8.1.3#1`. And `_`
116
+ is a word character, so `\b` finds nothing before the keyword in `_see 8.1_`,
117
+ which is ordinary Markdown emphasis. So the keyword follows `(\b|_)` — a word
118
+ boundary or an underscore — and the identifier is followed by anything but an
119
+ ASCII letter or digit. After a bare DocID, `#` is refused too, and so is `.`
120
+ unless it ends a sentence (the `\.[^0-9A-Za-z.#]` / `\.$` alternatives), so that
121
+ `see 8.1.` matches while `see 8.1.3` does not.
122
+
123
+ Where ripgrep is built with PCRE2, `-P` allows the clearer form:
124
+
125
+ ```bash
126
+ rg --no-ignore -P -n "(?<![0-9A-Za-z])([Ss]ee|[Pp]er) 8\.1(?![0-9A-Za-z#])(?!\.[0-9A-Za-z.#])" docs
127
+ ```
128
+
129
+ **Find everything a document governs.** This is the high-value query that
130
+ similarity search cannot answer — a generic contract governing many specific
131
+ documents that don't resemble it textually:
132
+
133
+ ```bash
134
+ rg --no-ignore -ln "^\s*([-*+]|[0-9]+[.)])\s*\[?8\.1[^0-9.#].*\(authority" docs
135
+ ```
136
+
137
+ Swap `authority` for `constraint` / `contract` / `dependency` to pull the other
138
+ edge types.
139
+
140
+ **Map the whole corpus, one line per document:**
141
+
142
+ ```bash
143
+ rg --no-ignore -n "^# [0-9]" docs
144
+ ```
145
+
146
+ **Find the document owning a concept by name** — the fallback when you have no
147
+ ID to follow:
148
+
149
+ ```bash
150
+ rg --no-ignore -li "idempotency key" docs
151
+ ```
152
+
153
+ ## 3 - What each reference obligates you to do
154
+
155
+ A References entry reads `{DocID} - {Title} ({direction} - {explanation})`. The
156
+ edge points **from this document to the cited one**. The middle column is what
157
+ ECR defines; the right-hand column is how to act on it, which ECR does not
158
+ define:
159
+
160
+ | Direction | Meaning (ECR) | Agent action (recommended) |
161
+ |---|---|---|
162
+ | **authority** | the cited document governs this one | Read it first. Treat it as the governing source. Flag apparent conflicts. |
163
+ | **constraint** | the cited document restricts this one | Check your change does not violate it. |
164
+ | **contract** | the cited document defines obligations or interfaces | Conform exactly — schemas, field names, typed outputs. |
165
+ | **dependency** | this document consumes the cited one | Read it to use it correctly. |
166
+
167
+ The `{explanation}` says *why* the edge exists. Use it to judge whether an edge
168
+ is relevant to your current change before you open the target.
169
+
170
+ **Precedence.** ECR does not define one. It records that a document governs
171
+ another; it does not say what to do when two governing documents disagree,
172
+ because resolving that requires reading what the constraints mean, which is
173
+ outside what ECR claims. Authority is therefore domain-scoped rather than a
174
+ ranking: each authority document governs its own domain and none outranks
175
+ another.
176
+
177
+ So when two authorities appear to conflict, surface it rather than picking a
178
+ winner. If the corpus declares its own precedence hierarchy, it does so in a map
179
+ document of its own — follow that. If it does not, say so and ask.
180
+
181
+ ## 4 - Grounding protocol
182
+
183
+ For any implementation task:
184
+
185
+ 1. **Orient.** Identify the DocID(s) the task touches.
186
+ 2. **Open the primary document** by its DocID.
187
+ 3. **Read its `## References` before writing code.** Open every `authority` and
188
+ `constraint` it cites; treat `contract` entries as obligations to satisfy;
189
+ read `dependency` entries you will consume. Use the `{explanation}` to skip
190
+ edges irrelevant to your change.
191
+ 4. **Follow inline `see`/`per` to the exact SectionID named** — open that one
192
+ section, not the whole document.
193
+ 5. **Before finishing, reverse-check at section granularity.** Grep backlinks to
194
+ the section you changed using the reverse-lookup patterns above. This is the step that surfaces the documents
195
+ relying on what you changed — the ones your target never mentions, and the
196
+ ones a change can silently break, because nothing in the file you are
197
+ reading points at them.
198
+ 6. **Load only what you need.** Pull sections, not the corpus. A few extra reads
199
+ of the right slice beat one read of everything.
200
+ 7. **On ambiguity, defer** to the domain authority rather than guessing.
201
+
202
+ ## 5 - Gotchas
203
+
204
+ - **Match numbers, not dashes.** Separators appear as hyphen `-`, en dash `–`
205
+ and em dash `—`, sometimes mixed within one line. Never anchor a pattern on a
206
+ dash.
207
+ - **Never match an identifier by string prefix.** `8.1` is not a prefix of
208
+ `8.10` in identifier terms, and `8.1.3` is a different document from section
209
+ `8.1#3`. Use the lookup patterns in this protocol rather than improvising.
210
+ - **`see` and `per` may be capitalised.** A pattern matching only lowercase
211
+ silently under-reports backlinks, which is the one failure this protocol
212
+ exists to prevent.
213
+ - **A bare number in prose is not an edge.** Only `see`/`per` inline references
214
+ and `## References` entries are load-bearing. But opening a document is cheap —
215
+ when unsure, look.
216
+ - **Every reference is found, but not every hit is a reference.** In a corpus
217
+ that passes the linter, these patterns find every reference it recognises.
218
+ They can also match text it does not: `per 60**s**` reads as `per 60s`, which
219
+ is prose, yet the pattern for `60` matches it. Read the line before treating
220
+ a hit as an edge.
221
+ - **Corpora drift.** A document may deviate from the convention. If a recipe
222
+ returns nothing, loosen it — drop the anchor, search by title text — before
223
+ concluding the target does not exist.