@rungs/cli 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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +196 -0
  3. package/modules/README.md +116 -0
  4. package/modules/adr/files/{{path}}/README.md +52 -0
  5. package/modules/adr/files/{{path}}/TEMPLATE.md +55 -0
  6. package/modules/adr/fragments/AGENTS.md +8 -0
  7. package/modules/adr/gates/adr.toml +65 -0
  8. package/modules/adr/module.toml +67 -0
  9. package/modules/audit/files/{{criteria_path}} +43 -0
  10. package/modules/audit/fragments/AGENTS.md +8 -0
  11. package/modules/audit/gates/audit.toml +48 -0
  12. package/modules/audit/module.toml +72 -0
  13. package/modules/audit/skills/assess/SKILL.md +62 -0
  14. package/modules/backlog/files/docs/{{root}}/BACKLOG.md +52 -0
  15. package/modules/backlog/files/docs/{{root}}/README.md +110 -0
  16. package/modules/backlog/files/docs/{{root}}/TEMPLATE.md +56 -0
  17. package/modules/backlog/files/docs/{{root}}/archive/README.md +13 -0
  18. package/modules/backlog/files/docs/{{root}}/items/README.md +13 -0
  19. package/modules/backlog/fragments/AGENTS.md +9 -0
  20. package/modules/backlog/gates/ids.toml +106 -0
  21. package/modules/backlog/module.toml +150 -0
  22. package/modules/backlog/rules/work-items.md +44 -0
  23. package/modules/backlog/skills/backlog-summary/SKILL.md +65 -0
  24. package/modules/backlog/skills/work-item/SKILL.md +96 -0
  25. package/modules/ci/files/{{workflow_path}} +43 -0
  26. package/modules/ci/gates/ci.toml +44 -0
  27. package/modules/ci/module.toml +74 -0
  28. package/modules/concurrency/files/docs/concurrent-sessions.md +87 -0
  29. package/modules/concurrency/fragments/AGENTS.md +10 -0
  30. package/modules/concurrency/fragments/gitattributes +15 -0
  31. package/modules/concurrency/gates/concurrency.toml +54 -0
  32. package/modules/concurrency/module.toml +113 -0
  33. package/modules/design-sync/fragments/AGENTS.md +8 -0
  34. package/modules/design-sync/gates/design.toml +70 -0
  35. package/modules/design-sync/module.toml +82 -0
  36. package/modules/design-sync/skills/design-align/SKILL.md +51 -0
  37. package/modules/design-sync/skills/design-pull/SKILL.md +50 -0
  38. package/modules/doc-authority/files/{{registry_path}} +59 -0
  39. package/modules/doc-authority/files/{{rules_path}} +51 -0
  40. package/modules/doc-authority/fragments/AGENTS.md +9 -0
  41. package/modules/doc-authority/gates/authority.toml +127 -0
  42. package/modules/doc-authority/module.toml +111 -0
  43. package/modules/findings/files/docs/{{backlog.root}}/FINDINGS.md +56 -0
  44. package/modules/findings/fragments/AGENTS.md +7 -0
  45. package/modules/findings/gates/findings.toml +68 -0
  46. package/modules/findings/module.toml +100 -0
  47. package/modules/findings/skills/record-finding/SKILL.md +63 -0
  48. package/modules/gates/files/.ai/gates.toml +49 -0
  49. package/modules/gates/fragments/AGENTS.md +8 -0
  50. package/modules/gates/fragments/gitignore +4 -0
  51. package/modules/gates/gates/structural.toml +127 -0
  52. package/modules/gates/module.toml +143 -0
  53. package/modules/gates/skills/harden-rule/SKILL.md +82 -0
  54. package/modules/instructions/files/.ai/rules/README.md +53 -0
  55. package/modules/instructions/files/AGENTS.md +104 -0
  56. package/modules/instructions/files/CLAUDE.md +11 -0
  57. package/modules/instructions/gates/core.toml +114 -0
  58. package/modules/instructions/module.toml +127 -0
  59. package/modules/release/fragments/AGENTS.md +8 -0
  60. package/modules/release/gates/release.toml +85 -0
  61. package/modules/release/module.toml +97 -0
  62. package/modules/release/skills/cut-release/SKILL.md +81 -0
  63. package/modules/session/files/{{archive}}/README.md +28 -0
  64. package/modules/session/files/{{path}} +56 -0
  65. package/modules/session/fragments/AGENTS.md +6 -0
  66. package/modules/session/gates/session.toml +63 -0
  67. package/modules/session/module.toml +72 -0
  68. package/modules/session/skills/close-session/SKILL.md +59 -0
  69. package/modules/skills/fragments/AGENTS.md +8 -0
  70. package/modules/skills/gates/skills.toml +94 -0
  71. package/modules/skills/module.toml +89 -0
  72. package/modules/skills/rules/skill-authoring.md +71 -0
  73. package/modules/specs/files/{{path}}/README.md +63 -0
  74. package/modules/specs/files/{{path}}/TEMPLATE.md +62 -0
  75. package/modules/specs/fragments/AGENTS.md +8 -0
  76. package/modules/specs/gates/specs.toml +119 -0
  77. package/modules/specs/module.toml +107 -0
  78. package/modules/workflows/fragments/AGENTS.md +8 -0
  79. package/modules/workflows/gates/workflows.toml +65 -0
  80. package/modules/workflows/module.toml +75 -0
  81. package/modules/workflows/rules/planning-tiers.md +46 -0
  82. package/modules/workflows/rules/reuse-decision.md +50 -0
  83. package/modules/workflows/skills/decompose/SKILL.md +75 -0
  84. package/package.json +42 -0
  85. package/src/add.ts +331 -0
  86. package/src/check.ts +216 -0
  87. package/src/cli.ts +411 -0
  88. package/src/detect.ts +246 -0
  89. package/src/engines.ts +260 -0
  90. package/src/engines2.ts +297 -0
  91. package/src/engines3.ts +194 -0
  92. package/src/glob.ts +101 -0
  93. package/src/lifecycle.ts +268 -0
  94. package/src/manifest.ts +108 -0
  95. package/src/render.ts +222 -0
  96. package/src/substitute.ts +78 -0
  97. package/src/types.ts +110 -0
@@ -0,0 +1,54 @@
1
+ # Gate table for the `concurrency` module.
2
+
3
+ # ── concurrency-no-integration-checkout ───────────────────────────────────────
4
+
5
+ [git_state]
6
+ refuse_checked_out = ["{{integration_branch}}"]
7
+ scope = "all-worktrees"
8
+ message = """
9
+ `{{integration_branch}}` is checked out in {worktree}. Nothing should hold it: `rungs land` runs
10
+ from wherever you are, verifies on a scratch ref, and advances the branch with a compare-and-swap.
11
+ Holding it checked out blocks every other session and does not prevent concurrent landing anyway —
12
+ switching to the scratch ref releases it mid-run, and two land processes have been measured running
13
+ at once under exactly that design.
14
+ """
15
+
16
+ # ── concurrency-generated-not-text-merged ─────────────────────────────────────
17
+ #
18
+ # Two failure modes, and the second is the quiet one: drivers declared in .gitattributes are inert
19
+ # until installed, so a fresh clone silently gets git's default merge on files that must never be
20
+ # text-merged.
21
+
22
+ [merge_driver_check]
23
+ attributes_file = ".gitattributes"
24
+ required_drivers = ["rungs-ledger", "rungs-generated"]
25
+ verify_installed = true
26
+ install_command = "rungs setup git"
27
+ message = """
28
+ The merge drivers named in .gitattributes are not installed in this clone, so they are inert and
29
+ merges are falling back to git's default. For a generated artifact that default is a clean text
30
+ merge of a file that is a fixed point of nothing — it surfaces later as a mismatch with an
31
+ uninformative diff. Run `rungs setup git` once per clone.
32
+ """
33
+
34
+ # ── self-tests ────────────────────────────────────────────────────────────────
35
+
36
+ [[self_test]]
37
+ gate = "concurrency-no-integration-checkout"
38
+ expect = "fail"
39
+ fixture = { worktrees = [{ branch = "{{integration_branch}}" }] }
40
+
41
+ [[self_test]]
42
+ gate = "concurrency-no-integration-checkout"
43
+ expect = "pass"
44
+ fixture = { worktrees = [{ branch = "feature/wi-001" }] }
45
+
46
+ [[self_test]]
47
+ gate = "concurrency-generated-not-text-merged"
48
+ expect = "fail"
49
+ fixture = { declared = ["rungs-ledger", "rungs-generated"], installed = [] }
50
+
51
+ [[self_test]]
52
+ gate = "concurrency-generated-not-text-merged"
53
+ expect = "pass"
54
+ fixture = { declared = ["rungs-ledger", "rungs-generated"], installed = ["rungs-ledger", "rungs-generated"] }
@@ -0,0 +1,113 @@
1
+ [module]
2
+ name = "concurrency"
3
+ version = "1.0.0"
4
+ rung = 5
5
+ summary = "Many sessions on one integration branch: a verified base to cut from, attributed failures, a land protocol that cannot redden the branch, and merge drivers per conflict class."
6
+
7
+ [requires]
8
+ modules = ["backlog", "gates", "ci"]
9
+
10
+ [conflicts]
11
+ modules = []
12
+
13
+ # ── THRESHOLD ─────────────────────────────────────────────────────────────────
14
+ #
15
+ # `add` states this and requires explicit confirmation:
16
+ #
17
+ # Below roughly five concurrent sessions on one integration branch, every
18
+ # mechanism here is pure overhead. It is a real tooling surface with its own
19
+ # failure modes, and it earns its cost only when sessions genuinely cannot see
20
+ # each other's work.
21
+ #
22
+ # Selling this to a rung-1 repo is the most likely way this tool does harm.
23
+
24
+ [threshold]
25
+ metric = "concurrent sessions on one integration branch"
26
+ minimum = 5
27
+ confirm = true
28
+
29
+ [params.integration_branch]
30
+ description = "The shared branch work lands on"
31
+ default = "main"
32
+
33
+ [params.green_prefix]
34
+ description = """
35
+ Ref marking the last merge that was actually verified. Branches are cut from this rather than from
36
+ the tip, so a session does not start on top of an unverified merge.
37
+ """
38
+ default = "green/"
39
+
40
+ [params.integ_prefix]
41
+ description = "Scratch ref a merge is verified on before the integration branch moves"
42
+ default = "integ/"
43
+
44
+ [[gates]]
45
+ id = "concurrency-no-integration-checkout"
46
+ kind = "declared"
47
+ engine = "git-state"
48
+ table = "gates/concurrency.toml"
49
+ tier = "fast"
50
+ why = """
51
+ Recorded as a correction, not a preference. The first design held the integration branch checked
52
+ out for the whole verification and called that single-writer. It was both worse than useless: it
53
+ blocked every other session — on one measured day every session in the repo sat in standby behind
54
+ one land — and it did not prevent concurrent landing anyway, because switching to the scratch ref
55
+ releases the branch mid-run. Two land processes were measured running at once.
56
+ """
57
+
58
+ [[gates]]
59
+ id = "concurrency-generated-not-text-merged"
60
+ kind = "declared"
61
+ engine = "merge-driver-check"
62
+ table = "gates/concurrency.toml"
63
+ tier = "fast"
64
+ why = """
65
+ Two branches that each regenerated an artifact produce hunks git interleaves cleanly into something
66
+ neither pipeline would emit. The failure surfaces later as a digest mismatch with an uninformative
67
+ diff. The driver refuses and prints the regenerate command instead.
68
+ """
69
+
70
+ [detect]
71
+ # `.gitattributes` was in this list and is a near-universal file — it reported
72
+ # axiom-mesh, a repo with 29 branches and no land protocol at all, as having
73
+ # concurrency tooling. A signature that matches nearly every repo is not a
74
+ # signature. What is actually distinctive is a declared merge driver.
75
+ paths = [".git/rungs-land.lock"]
76
+ # A custom merge driver declaration is what actually discriminates: 21 of them
77
+ # in the one repo of the four that runs a land protocol, and none in the other
78
+ # three. The file itself is near-universal, so it is scanned rather than counted.
79
+ marker_paths = [".gitattributes"]
80
+ markers = ["rungs:begin concurrency", "merge="]
81
+
82
+ [[detect.paradigm]]
83
+ id = "trunk-based"
84
+ compare = "docs/research/synthesis.md#35-concurrency-model"
85
+ note = """
86
+ Few branches and direct merges is not a lesser model — it is the right one below the threshold, and
87
+ two of the four source repos ran hundreds of commits that way. Report the branch and worktree
88
+ counts and let the operator decide; never install this because the mechanism is interesting.
89
+ """
90
+
91
+ [provenance]
92
+ sources = ["rift-forge"]
93
+ patterns = [
94
+ "green-ref",
95
+ "failure-attribution",
96
+ "land-protocol",
97
+ "lock-not-checkout",
98
+ "no-pre-land-full-verify",
99
+ "preflight",
100
+ "conflict-classes",
101
+ "regenerate-never-merge",
102
+ "id-claiming",
103
+ "worktree-lifecycle",
104
+ "ci-at-land-time",
105
+ ]
106
+ incident = """
107
+ rift-forge reached 401 branches and 51 live worktrees with many sessions branching off one
108
+ candidate and unable to see each other. This module ships its corrections included, because both
109
+ were expensive: the checkout-based lock that blocked every session and did not work, and the
110
+ pre-land full verify that widened the window the merge then conflicted in — three of five land
111
+ attempts refused in one measured session, every one after a 4–12 minute pre-verify, every one on
112
+ the same four generated artifacts.
113
+ """
@@ -0,0 +1,8 @@
1
+ <!-- rungs:begin design-sync@1.0.0 -->
2
+ ## Design
3
+
4
+ The design authority is external. Pull it with **`/design-pull`** into `{{mirror}}/` — generated,
5
+ never hand-edited — and decide what the pull means with **`/design-align`**. It owns layout and
6
+ visual language; it does not own this repo's technical constraints, and a conflict is a request to
7
+ send upstream. **Every delta is routed; there is no fourth option.**
8
+ <!-- rungs:end design-sync -->
@@ -0,0 +1,70 @@
1
+ # Gate table for the `design-sync` module.
2
+
3
+ # ── design-deltas-routed ──────────────────────────────────────────────────────
4
+ #
5
+ # Reads the pull record and requires every delta to name a route. The gate cannot judge whether a
6
+ # route is the right one — only that a decision was made and written down.
7
+
8
+ [register_schema]
9
+ file = "{{mirror}}/PULL-RECORD.md"
10
+ table = "Deltas"
11
+ required_cols = ["Delta", "Route", "Where"]
12
+ enum = { Route = ["implement", "defer", "upstream", "accept-as-is"] }
13
+ non_empty = ["Where"]
14
+ message = """
15
+ Delta "{delta}" has no route. Every difference is work we have decided to do, work we have decided
16
+ to defer, a disagreement to send upstream, or a mirror that is stale. A fifth state — noticed and
17
+ unrouted — is how the design and the implementation drift while both sides believe they are aligned.
18
+ """
19
+
20
+ # A deferred delta must carry a revisit trigger. "Later" is not a route.
21
+ [[register_schema.conditional]]
22
+ when = { Route = "defer" }
23
+ non_empty = ["Where"]
24
+ min_words = { Where = 4 }
25
+ message = "Delta \"{delta}\" is deferred with no revisit trigger. A deferral with no trigger is a decision to never do it, taken without saying so."
26
+
27
+ # ── design-mirror-not-edited ──────────────────────────────────────────────────
28
+
29
+ [[render_freshness]]
30
+ id = "design-mirror"
31
+ targets = ["{{mirror}}/**"]
32
+ generated_by = "rungs design pull"
33
+ detect = "local-modification"
34
+ message = """
35
+ {file} in the mirror has been edited locally. The mirror is generated and the next pull destroys
36
+ this — and until then it is a fact about the design system that the design system does not know.
37
+ Route it instead: a work item if we should change, an upstream request if they should.
38
+ """
39
+
40
+ # ── self-tests ────────────────────────────────────────────────────────────────
41
+
42
+ [[self_test]]
43
+ gate = "design-deltas-routed"
44
+ expect = "fail"
45
+ fixture = { row = { Delta = "spacing scale changed", Route = "", Where = "" } }
46
+
47
+ [[self_test]]
48
+ gate = "design-deltas-routed"
49
+ expect = "pass"
50
+ fixture = { row = { Delta = "spacing scale changed", Route = "implement", Where = "WI-051" } }
51
+
52
+ [[self_test]]
53
+ gate = "design-deltas-routed"
54
+ expect = "fail"
55
+ fixture = { row = { Delta = "new chart component", Route = "defer", Where = "later" } }
56
+
57
+ [[self_test]]
58
+ gate = "design-deltas-routed"
59
+ expect = "pass"
60
+ fixture = { row = { Delta = "new chart component", Route = "defer", Where = "revisit when analytics ships" } }
61
+
62
+ [[self_test]]
63
+ gate = "design-mirror-not-edited"
64
+ expect = "fail"
65
+ fixture = { modified = ["{{mirror}}/tokens.json"] }
66
+
67
+ [[self_test]]
68
+ gate = "design-mirror-not-edited"
69
+ expect = "pass"
70
+ fixture = { modified = [] }
@@ -0,0 +1,82 @@
1
+ [module]
2
+ name = "design-sync"
3
+ version = "1.0.0"
4
+ rung = 3
5
+ summary = "An external design authority pulled into a local mirror, with every delta routed to a work item, a future item, or an upstream change request — never silent divergence."
6
+
7
+ [requires]
8
+ modules = ["backlog", "skills"]
9
+
10
+ [conflicts]
11
+ modules = []
12
+
13
+ [params.source]
14
+ description = "The upstream design authority — a URL, a project id, or a repository."
15
+ default = ""
16
+ required = true
17
+ consumed_by = "design-pull"
18
+ # Behavioural: it tells the pull where to fetch from and never appears in a
19
+ # template. Deliberately not written into the skill body — the skill would then
20
+ # carry a URL that changes independently of it.
21
+
22
+ [params.mirror]
23
+ description = "Local mirror of the pulled design system. Generated; never hand-edited."
24
+ default = "design-system"
25
+
26
+ [params.request_path]
27
+ description = "Where upstream change requests are drafted before being sent"
28
+ default = "docs/design-requests"
29
+
30
+ [[gates]]
31
+ id = "design-deltas-routed"
32
+ kind = "declared"
33
+ engine = "register-schema"
34
+ table = "gates/design.toml"
35
+ tier = "fast"
36
+ why = """
37
+ Every difference between the mirror and the implementation is either work we have decided to do,
38
+ work we have decided to defer, or a disagreement to send upstream. A fourth category — noticed and
39
+ not routed — is how a design system and its implementation drift apart while both sides believe
40
+ they are aligned.
41
+ """
42
+
43
+ [[gates]]
44
+ id = "design-mirror-not-edited"
45
+ kind = "declared"
46
+ engine = "render-freshness"
47
+ table = "gates/design.toml"
48
+ tier = "fast"
49
+ why = "A hand-edit in the mirror is a local change that the next pull silently destroys, and until then it is a fact about the design system that the design system does not know."
50
+
51
+ [skills.design-pull]
52
+ # Read-only against upstream. Safe for a model to run unprompted.
53
+
54
+ [skills.design-align]
55
+ # No extensions: it writes backlog items and drafts requests, both of which
56
+ # are reversible and reviewable. It does not send anything upstream.
57
+
58
+ [detect]
59
+ paths = ["design-system/**", "docs/**/design-tokens*", ".design/**"]
60
+ markers = ["rungs:begin design-sync"]
61
+
62
+ [[detect.paradigm]]
63
+ id = "design-in-repo"
64
+ paths = ["**/tokens.{json,css,scss}", "**/theme.{ts,css}"]
65
+ compare = "docs/research/synthesis.md#2-convergences--where-independent-repos-agreed"
66
+ note = """
67
+ A design system authored *in* this repo is not an external authority and does not need syncing —
68
+ it needs the ordinary rules for shared code. This module is for the case where somebody else owns
69
+ the design and disagreements have to travel back to them. Report and stop.
70
+ """
71
+
72
+ [provenance]
73
+ sources = ["rift-forge", "hexguard-templates"]
74
+ patterns = ["external-authority-precedence", "two-way-design-sync"]
75
+ incident = """
76
+ hexguard-templates states the precedence rule that makes an external authority workable: the design
77
+ project is "layout/visual guidance, not a functional spec, and its output must still satisfy this
78
+ repo's technical constraints". Without a stated precedence, an external source either gets ignored
79
+ or overrides constraints it knows nothing about. rift-forge industrialised the same integration into
80
+ a down-pull plus an alignment pass whose rule is that every delta is routed somewhere — never
81
+ silent divergence, and never forced convergence either.
82
+ """
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: design-align
3
+ description: >-
4
+ Reconcile the pulled design mirror against what is actually implemented, routing every difference
5
+ to a work item, a deferred item, or an upstream change request. Use after a design pull, or when
6
+ asked to "align with the design", "does this match the mock", "triage the design deltas", or
7
+ "what does the new design mean for us". Pulling the mirror down is /design-pull; this decides
8
+ what the pull means.
9
+ ---
10
+
11
+ # Align with the design
12
+
13
+ **Every delta is routed. There is no fourth option.**
14
+
15
+ A difference that is noticed and not routed is how a design system and its implementation drift
16
+ apart while both sides believe they are aligned — and the drift is discovered by a user, or by
17
+ someone rebuilding a screen and finding two sources of truth.
18
+
19
+ ## Precedence, before anything
20
+
21
+ The design authority owns **layout, visual language, spacing, colour, motion intent**. It does not
22
+ own this repo's technical constraints, accessibility floor, or component boundaries. A design that
23
+ requires breaking one of those is a **disagreement to send upstream**, not an instruction.
24
+
25
+ State which side owns a contested decision *before* deciding the delta — most arguments here are
26
+ really arguments about ownership.
27
+
28
+ ## For each delta, choose exactly one
29
+
30
+ | Route | When | What you write |
31
+ | --- | --- | --- |
32
+ | **Implement now** | It is in scope, and the current phase covers it | A work item, with the delta as its rationale |
33
+ | **Defer** | Real, agreed, but belongs to a later phase | A work item marked deferred, **with the revisit trigger** — not a vague "later" |
34
+ | **Send upstream** | The design conflicts with a constraint it does not know about, or is internally inconsistent | A draft in `{{request_path}}`, stating the constraint and what we need |
35
+ | **Accept as-is** | The implementation is right and the mirror is stale | Nothing local — but say so in the pull's record, or the same delta reappears next pull |
36
+
37
+ ## What makes this fail
38
+
39
+ - **Batching deltas into one "design alignment" item.** They have different owners, different
40
+ phases, and different answers. One item hides all of that and gets deferred as a lump.
41
+ - **Implementing ahead of the roadmap** because the design shows it. A design is not a schedule.
42
+ - **Silently adjusting the mirror** to match what is built. The mirror is generated; the next pull
43
+ destroys the edit, and until then it is a fact about the design that the designer does not know.
44
+ - **Treating a stale mirror as authoritative.** Check when the pull happened before trusting a
45
+ delta.
46
+
47
+ ## Finish
48
+
49
+ Report the counts per route, and **how many deltas were examined**. A pass that found nothing and a
50
+ pass that compared nothing produce the same output, and only one of them means the design is
51
+ implemented.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: design-pull
3
+ description: >-
4
+ Pull the design system down from the upstream authority into the local mirror, and record what
5
+ changed since the last pull. Use when asked to "pull the design", "sync the design system", "get
6
+ the latest tokens/components", or before starting UI work that should match a current design.
7
+ Down-sync only — it never pushes local changes upstream. Deciding what the pull means is
8
+ /design-align.
9
+ ---
10
+
11
+ # Pull the design system
12
+
13
+ **Down-sync only.** This skill never sends anything upstream; that is `/design-align`'s change
14
+ request, drafted for a person to send.
15
+
16
+ ## 1. Record where you are starting
17
+
18
+ Note the mirror's current state before pulling — what came down last time and when. Without it,
19
+ "what changed" degrades into "everything looks different", which is not a delta list.
20
+
21
+ ## 2. Pull into `{{mirror}}/`
22
+
23
+ The mirror is **generated**. Anything hand-edited there is destroyed by this step, which is why
24
+ `design-mirror-not-edited` exists — if it has fired, resolve that before pulling or the edit
25
+ disappears along with whatever it was compensating for.
26
+
27
+ ## 3. Report what changed, in design terms
28
+
29
+ Not a file diff. Group by what a person would recognise:
30
+
31
+ - tokens added, changed, removed
32
+ - components added, changed, removed
33
+ - layout or spacing rules changed
34
+ - anything **removed** — the most consequential category and the easiest to miss, because a removal
35
+ looks like nothing rather than like a change
36
+
37
+ ## 4. Say what you could not tell
38
+
39
+ An upstream that reorganised its files produces a diff that looks like a rewrite. Say so rather
40
+ than reporting hundreds of false deltas — an alignment pass fed noise gets abandoned, and the real
41
+ deltas go with it.
42
+
43
+ ## 5. Stop
44
+
45
+ **Do not implement anything.** Do not open work items. Do not adjust components to match. The pull
46
+ establishes what upstream says; `/design-align` decides what that means here, against precedence
47
+ rules and the current phase.
48
+
49
+ Hand off with the delta list and the pull date. That date is what makes the next reader able to
50
+ tell a live delta from a stale one.
@@ -0,0 +1,59 @@
1
+ **Authoritative for:** which document owns which topic.
2
+ **Not authoritative for:** the content of any topic listed below.
3
+
4
+ # Document ownership
5
+
6
+ The arbiter. **When a question arises about where something belongs, it is resolved here first,
7
+ before any content is written.** If the answer is missing, add the row before writing.
8
+
9
+ ## The registry
10
+
11
+ The third column is what makes this enforceable rather than aspirational: it converts "one source
12
+ of truth" from a principle into a lookup, and it is what `rungs check` reads.
13
+
14
+ | Topic | Owner | Must NOT appear in |
15
+ | --- | --- | --- |
16
+ | *(example)* Build and test commands | `AGENTS.md` | `README.md`, `docs/**` |
17
+ | | | |
18
+
19
+ <!-- Add a row before writing content whose home is unclear. A row costs a minute; a topic living
20
+ in two documents costs a divergence nobody notices until they disagree. -->
21
+
22
+ ## The rules this enforces
23
+
24
+ **No fact is stated in two documents.** If a value, rule or contract already exists in its owning
25
+ document, the second one references it with a link — never restates it, **not even as a summary.**
26
+
27
+ **Paraphrase is not permitted.** This is the one people argue with, so it is worth being explicit:
28
+ a paraphrase looks maintained while it decays. A summary that "just gives the gist" is a second
29
+ statement of the fact, and when the original changes, the gist becomes wrong while still reading
30
+ as deliberate.
31
+
32
+ **Drift is a bug**, not untidiness. A document that paraphrases rather than references *will*
33
+ diverge — the only question is when it is noticed and what was built on it in the meantime.
34
+
35
+ **No redirect stubs.** A file that exists only to say "go elsewhere" gets cited, and the citation
36
+ looks authoritative. Delete it and repoint the citers.
37
+
38
+ **Review outbound links on every edit.** After editing, confirm the documents you link to still
39
+ say what you are citing them for. This is the step that catches drift while it is cheap.
40
+
41
+ ## Scope headers
42
+
43
+ Every document opens with both blocks, so a reader who opened the wrong file learns it in one line:
44
+
45
+ ```markdown
46
+ **Authoritative for:** …
47
+ **Not authoritative for:** …
48
+ ```
49
+
50
+ The repository root `README.md` is exempt — it is a navigation page.
51
+
52
+ **A stub may contain only scope headers and cross-references** until it is explicitly promoted.
53
+ This is what stops a placeholder quietly accreting content it does not own.
54
+
55
+ ## When two documents both claim a topic
56
+
57
+ Do not split the difference, and do not pick the better-written one. Decide which is the **owner**,
58
+ move the content there, and leave a link. A topic owned by two documents is owned by neither, and
59
+ the next reader will find whichever one search puts first.
@@ -0,0 +1,51 @@
1
+ **Authoritative for:** which cross-cutting working rules exist, and which surfaces restate each one.
2
+ **Not authoritative for:** why any rule is what it is — that lives in the rule's own authority document.
3
+
4
+ # Working rules
5
+
6
+ A **working rule** is how we do something: how an id is claimed, how a dataset is republished,
7
+ which source outranks which. It is different from a domain fact in one specific way, and it is
8
+ worse: a stale domain fact produces a number someone can check, while **a stale working rule
9
+ produces someone confidently doing the retired thing, correctly, all day.**
10
+
11
+ A working rule lives in more places than its authority:
12
+
13
+ | Surface | What it holds | What keeps it true |
14
+ | --- | --- | --- |
15
+ | the **authority document** | the rule, and *why* — the only place the reasoning belongs | review |
16
+ | the **always-on document** | the one-paragraph version every session reads | this registry's gate |
17
+ | the **skills that execute it** | the step-by-step form, where it is actually met | this registry's gate |
18
+ | the **tool that automates it** | the rule made mechanical, and its self-test | its own gate |
19
+
20
+ ## The registry
21
+
22
+ Each rule is declared with the surfaces that restate it. A surface that **engages the topic** must
23
+ carry the rule's current vocabulary and must not carry the retired instruction.
24
+
25
+ | Rule | Authority | Surfaces that restate it | Retired wording |
26
+ | --- | --- | --- | --- |
27
+ | *(example)* Ids are claimed on your own branch | `docs/backlog/README.md` | `AGENTS.md`, `skills/work-item` | "claim on the integration branch" |
28
+ | | | | |
29
+
30
+ ## Four rules about changing a rule
31
+
32
+ 1. **Fix the authority first, then the citers.** A citer corrected against a stale authority is a
33
+ second wrong statement, and the next reader cannot tell which one won.
34
+ 2. **A citation is not propagation.** *"See §3"* ages into a **false claim** the moment §3 changes
35
+ — and it reads as verified precisely because it names a source.
36
+ 3. **Declare the rule here** when it is cross-cutting, with its surfaces. That is what turns "we
37
+ should remember to update the skills" into a build failure. Adding a cross-cutting rule without
38
+ a row is how the next several get missed.
39
+ 4. **A tool that invalidates a generated artifact must say so in its own output.** The standing
40
+ rule: **a green check means "not yet regenerated", never "current".**
41
+
42
+ ## Exemptions
43
+
44
+ Prose that *quotes* a retired rule to explain why it was retired is exempted by name and reason:
45
+
46
+ ```markdown
47
+ <!-- working-rule-ok: <rule-id> — quotes the retired wording to explain the change -->
48
+ ```
49
+
50
+ **The marker is ignored unless it states a reason.** An escape hatch nobody has to justify is not
51
+ an escape hatch, it is an off switch. Never exempt by rewriting the history.
@@ -0,0 +1,9 @@
1
+ <!-- rungs:begin doc-authority@1.0.0 -->
2
+ ## Document ownership
3
+
4
+ Before writing content whose home is unclear, resolve it in
5
+ [`{{registry_path}}`]({{registry_path}}) — it is the arbiter, and its third column says where a
6
+ topic must **not** appear. **No fact is stated in two documents, and paraphrase is not permitted**:
7
+ a paraphrase looks maintained while it decays. Changing a cross-cutting working rule means updating
8
+ every surface in [`{{rules_path}}`]({{rules_path}}) — **a citation is not propagation.**
9
+ <!-- rungs:end doc-authority -->