xdrs-core 0.13.0 → 0.14.2

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 (29) hide show
  1. package/.xdrs/_core/adrs/index.md +2 -6
  2. package/.xdrs/_core/adrs/principles/001-xdrs-core.md +9 -1
  3. package/.xdrs/_core/adrs/principles/002-xdr-standards.md +12 -17
  4. package/.xdrs/_core/adrs/principles/003-skill-standards.md +1 -1
  5. package/.xdrs/_core/adrs/principles/004-article-standards.md +1 -1
  6. package/.xdrs/_core/adrs/principles/006-research-standards.md +2 -2
  7. package/.xdrs/_core/adrs/principles/007-plan-standards.md +132 -0
  8. package/.xdrs/_core/adrs/principles/articles/001-xdrs-overview.md +19 -7
  9. package/.xdrs/_core/adrs/principles/skills/001-lint/001-lint.test.int.js +40 -0
  10. package/.xdrs/_core/adrs/principles/skills/001-lint/001-lint.test.int.report +23 -0
  11. package/.xdrs/_core/adrs/principles/skills/001-lint/SKILL.md +3 -3
  12. package/.xdrs/_core/adrs/principles/skills/002-write-xdr/002-write-xdr.test.int.js +24 -0
  13. package/.xdrs/_core/adrs/principles/skills/002-write-xdr/002-write-xdr.test.int.report +14 -0
  14. package/.xdrs/_core/adrs/principles/skills/002-write-xdr/SKILL.md +15 -7
  15. package/.xdrs/_core/adrs/principles/skills/003-write-skill/003-write-skill.test.int.js +24 -0
  16. package/.xdrs/_core/adrs/principles/skills/003-write-skill/003-write-skill.test.int.report +14 -0
  17. package/.xdrs/_core/adrs/principles/skills/003-write-skill/SKILL.md +1 -1
  18. package/.xdrs/_core/adrs/principles/skills/004-write-article/004-write-article.test.int.js +24 -0
  19. package/.xdrs/_core/adrs/principles/skills/004-write-article/004-write-article.test.int.report +17 -0
  20. package/.xdrs/_core/adrs/principles/skills/004-write-article/SKILL.md +1 -1
  21. package/.xdrs/_core/adrs/principles/skills/005-write-research/005-write-research.test.int.js +3 -19
  22. package/.xdrs/_core/adrs/principles/skills/005-write-research/005-write-research.test.int.report +5 -12
  23. package/.xdrs/_core/adrs/principles/skills/005-write-research/SKILL.md +1 -1
  24. package/.xdrs/_core/adrs/principles/skills/006-write-plan/SKILL.md +151 -0
  25. package/README.md +10 -3
  26. package/lib/lint.js +86 -38
  27. package/lib/testPrompt.js +1 -0
  28. package/package.json +1 -1
  29. package/.xdrs/_core/adrs/principles/researches/001-research-and-decision-lifecycle.md +0 -99
@@ -50,7 +50,7 @@ Quick test:
50
50
 
51
51
  1. List `.xdrs/[scope]/[type]/[subject]/skills/` for existing skills. If one already covers the goal, extend or reference it instead of creating a duplicate.
52
52
  2. Read all XDRs relevant to the skill's domain to collect rules and cross-references.
53
- 3. Evaluate XDR metadata before operationalizing those rules. `Status:` decides whether a decision is eligible to be used, and omitted `Status:` means `Active`; `Valid:` decides whether that active decision is in force at the current moment, `Applied to:` decides whether it fits the intended task context, and the decision text defines any remaining boundaries. Keep inactive, out-of-window, or out-of-scope XDRs as background only.
53
+ 3. Evaluate XDR metadata before operationalizing those rules. All documents present in the collection are considered active. `Valid:` determines the convergence date for adoption, `Applied to:` determines whether the decision fits the intended task context, and the decision text defines any remaining boundaries. Keep out-of-window or out-of-scope XDRs as background only.
54
54
  4. Decide whether the skill is merely guidance or is being referenced by an XDR as a mandatory procedure. Do not encode policy in the skill unless it comes from a referenced XDR.
55
55
 
56
56
  ### Phase 4: Write the SKILL.md
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { copilotCmd, testPrompt } = require('xdrs-core');
5
+
6
+ const REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..', '..', '..');
7
+
8
+ jest.setTimeout(300000);
9
+
10
+ test('004-write-article creates a local principles article', async () => {
11
+ const err = await testPrompt(
12
+ {
13
+ workspaceRoot: REPO_ROOT,
14
+ workspaceMode: 'copy',
15
+ ...copilotCmd(REPO_ROOT),
16
+ },
17
+ 'Create a short article for new users explaining the overall principles of xdrs, element types and the role of each document in adrs',
18
+ 'Verify that an article markdown file was created under .xdrs/_local/adrs/principles/articles/ and that it has references to 001-xdrs-core.md',
19
+ null,
20
+ true
21
+ );
22
+
23
+ expect(err).toBe('');
24
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "Create a short article for new users exp-73060d4f": {
3
+ "result": "success",
4
+ "contextFiles": [
5
+ ".xdrs/_core/adrs/index.md",
6
+ ".xdrs/_core/adrs/principles/001-xdrs-core.md",
7
+ ".xdrs/_core/adrs/principles/004-article-standards.md",
8
+ ".xdrs/_core/adrs/principles/articles/001-xdrs-overview.md",
9
+ ".xdrs/_local/bdrs/index.md",
10
+ ".xdrs/_local/bdrs/operations/001-agent-behavior-validation-procedure.md",
11
+ ".xdrs/index.md",
12
+ "AGENTS.md",
13
+ "README.md"
14
+ ],
15
+ "contextHash": "75745a424155326ee56008bcf923999e"
16
+ }
17
+ }
@@ -47,7 +47,7 @@ If the article spans more than one subject, place it in `principles`.
47
47
  ### Phase 4: Research XDRs and Skills to Synthesize
48
48
 
49
49
  1. Read all XDRs, Research documents, and Skills relevant to the article topic across all scopes listed in `.xdrs/index.md`.
50
- 2. Evaluate XDR metadata before synthesizing guidance. Use `Status:` to determine whether a decision is eligible to be current guidance, treating omitted `Status:` as `Active`; use `Valid:` to determine whether that active decision is in force for the article's time horizon, `Applied to:` to determine whether it fits the audience or context being discussed, and the decision text itself for any remaining applicability boundaries.
50
+ 2. Evaluate XDR metadata before synthesizing guidance. All documents present in the collection are considered active. Use `Valid:` to determine the convergence date for adoption, `Applied to:` to determine whether the decision fits the audience or context being discussed, and the decision text itself for any remaining applicability boundaries.
51
51
  3. Identify the key points a reader needs to understand the topic end-to-end.
52
52
  4. Collect XDR IDs and file paths for cross-references. Never copy decision text verbatim; link to it.
53
53
 
@@ -5,23 +5,7 @@ const { copilotCmd, testPrompt } = require('xdrs-core');
5
5
 
6
6
  const REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..', '..', '..');
7
7
 
8
- jest.setTimeout(300000);
9
-
10
- test('check', async () => {
11
- const err = await testPrompt(
12
- {
13
- workspaceRoot: REPO_ROOT,
14
- workspaceMode: 'in-place',
15
- ...copilotCmd(REPO_ROOT),
16
- },
17
- 'Reply ONLY with "READY" after checking if SKILL 001 has any contents',
18
- 'Verify that the final output is ONLY "READY" and that it read file 001-lint/SKILL.md',
19
- null,
20
- true
21
- );
22
-
23
- expect(err).toBe('');
24
- });
8
+ jest.setTimeout(600000);
25
9
 
26
10
  test('005-write-research creates an IMRAD research document in copy mode', async () => {
27
11
  const err = await testPrompt(
@@ -30,8 +14,8 @@ test('005-write-research creates an IMRAD research document in copy mode', async
30
14
  workspaceMode: 'copy',
31
15
  ...copilotCmd(REPO_ROOT),
32
16
  },
33
- 'Create a very small research document with the following data: We measured the installation time in our monorepo and pnpm is 3.5x faster than Yarn when installing dependencies. We recommend using PNPM in our monorepo to speed up our productivity as it seems very easy to use and have a better internal hoisting mechanism.',
34
- 'Verify that a research file was created under .xdrs/_local/edrs/devops/researches/, that it contains the sections Abstract, Introduction, Methods, Results, Discussion, Conclusion, and References, and that the content contains all the provided data in input prompt, and doesn\'t contain more than 20% of additional information outside the central topic.',
17
+ 'Create a very small research document with the following data: Java vs Python for datascience projects. Java has much less libraries and community momentum than Python. Java is faster, but in general our DS applications doesn\'t require high performance. Is some cases we could use Spark for data and very specific ETL and transformations, but in general Python should be the norm for Data Science projects, especially in the early phases.',
18
+ 'Verify that a research file was created under .xdrs/_local/edrs/application/researches/, that it contains the sections Abstract, Introduction, Methods, Results, Discussion, Conclusion, and References, have the right ratio of words on the sections (not worse than 50% in deviation) and that the content contains all the provided data in input prompt, and doesn\'t contain more than 20% of additional information outside the central topic. Check also if there is at least one comparison table between the options, ',
35
19
  null,
36
20
  true
37
21
  );
@@ -1,22 +1,15 @@
1
1
  {
2
- "Reply ONLY with \"READY\" after checking i-a61b0904": {
3
- "result": "success",
4
- "contextFiles": [
5
- ".xdrs/_core/adrs/principles/skills/001-lint/SKILL.md",
6
- "AGENTS.md"
7
- ],
8
- "contextHash": "3dcbcc0a03f4d3b2a797c28165f6f68a"
9
- },
10
- "Create a very small research document wi-ea3740cd": {
2
+ "Create a very small research document wi-7896a781": {
11
3
  "result": "success",
12
4
  "contextFiles": [
5
+ ".github/skills/005-write-research/005-write-research.test.int.js",
6
+ ".xdrs/_core/adrs/index.md",
13
7
  ".xdrs/_core/adrs/principles/001-xdrs-core.md",
14
8
  ".xdrs/_core/adrs/principles/006-research-standards.md",
15
- ".xdrs/_local/bdrs/index.md",
16
- ".xdrs/_local/edrs/devops/researches/001-pnpm-vs-yarn-install-speed-monorepo.md",
9
+ ".xdrs/_local/edrs/languages/researches/001-java-vs-python-for-datascience.md",
17
10
  ".xdrs/index.md",
18
11
  "AGENTS.md"
19
12
  ],
20
- "contextHash": "a8ffde30ac3757f1185fee620f526720"
13
+ "contextHash": "2f06eb73c19194e53321d4b75c0fc214"
21
14
  }
22
15
  }
@@ -45,7 +45,7 @@ Consult `001-xdrs-core` while making each choice in this phase. The summaries be
45
45
  ### Phase 3: Research Existing Artifacts
46
46
 
47
47
  1. Read relevant XDRs across all scopes listed in `.xdrs/index.md`.
48
- 2. Evaluate XDR metadata before treating any decision as current context. `Status:` decides whether a decision is eligible to be used, and omitted `Status:` means `Active`; `Valid:` decides whether that active decision is in force at the current moment, `Applied to:` decides whether it fits the intended task context, and the decision text defines any remaining boundaries. Keep inactive, out-of-window, or out-of-scope XDRs as background only.
48
+ 2. Evaluate XDR metadata before treating any decision as current context. All documents present in the collection are considered active. `Valid:` determines the convergence date for adoption, `Applied to:` determines whether the decision fits the intended task context, and the decision text defines any remaining boundaries. Keep out-of-window or out-of-scope XDRs as background only.
49
49
  3. Read existing research documents in the same or overlapping subjects to avoid duplicating the same study.
50
50
  4. Read related skills or articles if they contain context, implementation limits, or terminology that must be reflected.
51
51
  5. Collect links that should appear in the final `## References` section.
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: 006-write-plan
3
+ description: >
4
+ Creates a new plan document following XDR plan standards: selects scope, type, subject, and number;
5
+ then writes a focused execution plan with problem context, proposed solution, approach, milestones, and deliverables.
6
+ Activate this skill when the user asks to create, add, or write a plan, project plan, or execution plan within an XDR project.
7
+ metadata:
8
+ author: flaviostutz
9
+ version: "1.0"
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ Guides the creation of a well-structured plan document by following `_core-adr-007`, consulting `xdr-standards` for every core element definition, researching related XDRs and existing plans, and producing a focused execution document that connects to the decisions, research, and skills it relates to.
15
+
16
+ ## Instructions
17
+
18
+ ### Phase 1: Understand the Plan Goal
19
+
20
+ 1. Read `.xdrs/_core/adrs/principles/007-plan-standards.md` in full to internalize the template, placement rules, numbering rules, and the constraint that plans are ephemeral and must be deleted after implementation.
21
+ 2. Read `.xdrs/_core/adrs/principles/001-xdrs-core.md` in full before defining the plan's core elements. Treat it as the canonical source for how to choose and write type, scope, subject, numbering, naming, and folder placement.
22
+ 3. Identify the problem being solved, the proposed solution, and the expected timeline from user input or context. Do NOT proceed without a clear problem statement and proposed solution. Ask the user if these are not clear.
23
+
24
+
25
+ ### Phase 2: Select Scope, Type, and Subject
26
+
27
+ Consult `001-xdrs-core` while making each choice in this phase. The summaries below are orientation only; when any detail is unclear, the standard decides.
28
+
29
+ **Scope** — use `_local` unless the user explicitly names another scope.
30
+
31
+ **Type** — match the type of the XDRs the plan primarily implements or relates to (`adrs`, `bdrs`, or `edrs`).
32
+ - **BDR**: business process, product policy, strategic rule, operational procedure
33
+ - **ADR**: system context, integration pattern, overarching architectural choice
34
+ - **EDR**: specific tool/library, coding practice, testing strategy, project structure, pipelines
35
+
36
+ **Subject** — pick the subject that best matches the plan's topic. If the plan spans more than one subject, place it in `principles`.
37
+
38
+ ### Phase 3: Assign a Number and Name
39
+
40
+ 1. List `.xdrs/[scope]/[type]/[subject]/plans/` (create the folder if it does not exist).
41
+ 2. Find the highest existing plan number in that namespace and increment by 1. Never reuse numbers.
42
+ 3. Choose a short lowercase kebab-case title that describes the initiative clearly.
43
+ - Good: `checkout-performance`, `onboarding-redesign`, `api-migration-v2`
44
+ - Avoid: `plan`, `project`, `misc`
45
+
46
+ ### Phase 4: Research Related Artifacts
47
+
48
+ 1. Read all XDRs, Research documents, Skills, and existing Plans relevant to the plan topic across all scopes listed in `.xdrs/index.md`.
49
+ 2. Evaluate XDR metadata before treating any decision as current context. All documents present in the collection are considered active. `Valid:` determines the convergence date for adoption, `Applied to:` determines whether the decision fits the intended context, and the decision text defines any remaining boundaries.
50
+ 3. Identify Decisions that this plan implements, Research that informs the planning, and any existing Plans that overlap.
51
+ 4. Collect artifact IDs and file paths for cross-references.
52
+
53
+ ### Phase 5: Write the Plan
54
+
55
+ Use the mandatory template from `007-plan-standards`:
56
+
57
+ ```markdown
58
+ # [scope]-plan-[number]: [Short Title]
59
+
60
+ ## Executive Summary
61
+
62
+ [Required. Bullet points summarizing all sections below. Under 500 words.]
63
+
64
+ ## Context and Problem Statement
65
+
66
+ [Required. Why are we executing this plan? What is the impact? Who is impacted? Under 200 words.]
67
+
68
+ ## Proposed Solution
69
+
70
+ [Required. What we expect to achieve. Under 200 words.]
71
+
72
+ ## Acceptance Criteria
73
+
74
+ [Optional. Expected result and how to verify the goal is achieved. Under 100 words.]
75
+
76
+ Expected end date: YYYY-MM-DD
77
+
78
+ ## Approach
79
+
80
+ [Optional. Strategy and high-level how. Under 300 words.]
81
+
82
+ ## Key Deliverables
83
+
84
+ [Optional. Main outputs needed. Under 300 words.]
85
+
86
+ ## Key Resources
87
+
88
+ [Optional. Equipment, people, budget, dependencies. Under 100 words.]
89
+
90
+ ## Milestones
91
+
92
+ [Optional. Goals with acceptance criteria, owners, and due dates. Under 1000 words per milestone.]
93
+
94
+ ## Risks Identified
95
+
96
+ [Optional. Risks with description and mitigation strategy. Under 1000 words.]
97
+
98
+ ## References
99
+
100
+ - [Related XDR or artifact](relative/path.md) - Brief description of relevance
101
+ ```
102
+
103
+ Rules to apply while drafting:
104
+
105
+ - Focus on the problem, solution, and approach. Avoid bloating with generic project management content.
106
+ - Link to Decisions the plan implements, Research that informs it, and Skills that guide execution.
107
+ - The Expected end date must be in ISO format (YYYY-MM-DD) and should not be more than 2 years from the plan creation date.
108
+ - If the plan scope is too large for 2 years, break it into multiple plans.
109
+ - Remember that this plan must be deleted after full implementation. Write it with that ephemeral nature in mind.
110
+ - Prefer plain Markdown, tables, or ASCII art for structure and flow.
111
+ - If the plan genuinely needs local images or supporting files, store them in `.xdrs/[scope]/[type]/[subject]/plans/assets/` and link with a relative path.
112
+ - Use lowercase file names. Never use emojis.
113
+
114
+ ### Phase 6: Place and Register
115
+
116
+ 1. Save the file at `.xdrs/[scope]/[type]/[subject]/plans/[number]-[short-title].md`.
117
+ 2. Add a link to the plan in the canonical index for that scope+type (`.xdrs/[scope]/[type]/index.md`).
118
+ 3. Add back-references in the XDRs, Research documents, and Skills that the plan relates to, under their `## References` section.
119
+
120
+ ### Phase 7: Verify with Lint
121
+
122
+ 1. Run the CLI lint utility from the repository root:
123
+ ```
124
+ npx -y xdrs-core lint .
125
+ ```
126
+ 2. Fix all reported errors before considering the task complete.
127
+
128
+ ## Examples
129
+
130
+ **Input:** "Create a plan for migrating our API to v2."
131
+
132
+ **Expected actions:**
133
+ 1. Read `007-plan-standards.md`.
134
+ 2. Topic: API v2 migration. Scope: `_local`.
135
+ 3. Type: `adrs` (architectural). Subject: `integration` or `application`.
136
+ 4. Research related XDRs about API design and integration patterns.
137
+ 5. Draft the plan with clear problem, solution, milestones, and expected end date.
138
+ 6. Save, register in canonical index, and lint.
139
+
140
+ ## Edge Cases
141
+
142
+ - If a plan is too large (more than 2 years), split it into multiple smaller plans. Each plan should be independently actionable and produce its own deliverables.
143
+ - If a plan spawns sub-plans during implementation, each sub-plan is a separate plan document in the appropriate subject folder. Link them in the References section.
144
+ - If a plan is fully implemented, delete it and confirm that all lasting outputs (Decisions, Skills, Articles, etc.) are properly linked and indexed.
145
+ - If the user asks for a plan that is really just a decision, guide them to create an XDR instead.
146
+
147
+ ## References
148
+
149
+ - [_core-adr-001 - XDRs core](../../001-xdrs-core.md)
150
+ - [_core-adr-007 - Plan standards](../../007-plan-standards.md)
151
+ - [_core-adr-002 - XDR standards](../../002-xdr-standards.md)
package/README.md CHANGED
@@ -12,12 +12,13 @@ This project defines a standard for organizing XDRs that satisfies the following
12
12
 
13
13
  ## XDR elements
14
14
 
15
- Every XDR package contains four types of documents:
15
+ Every XDR package contains five types of documents:
16
16
 
17
17
  - **Decision Records (XDRs)** — Architectural (ADR), Business (BDR), or Engineering (EDR) records that capture a single decision, its rationale, and the rules that follow from it. They are the source of truth.
18
18
  - **Research** — Exploratory documents that capture the problem being investigated, constraints or requirements, findings, and option tradeoffs that back a decision during its lifecycle. One research document may inform multiple downstream decisions, but it is not a replacement for the Decision Record.
19
19
  - **Skills** — Step-by-step procedural guides that can be followed by humans, AI agents, or both. Skills are task-based artifacts with a concrete outcome and should include enough detail to verify the task was completed correctly. A skill may start as a fully manual procedure and evolve toward partial or full AI automation over time.
20
20
  - **Articles** — Synthetic explanatory texts that combine information from multiple XDRs, Research documents, and Skills around a specific topic or audience. They never replace XDRs as source of truth.
21
+ - **Plans** — Ephemeral execution documents that describe a problem, proposed solution, and the approach and activities needed to solve it. Plans have a clear start and end and must be deleted after full implementation. Lasting outputs are captured as Decisions, Skills, Articles, or other artifacts.
21
22
 
22
23
  ## Getting started
23
24
 
@@ -65,7 +66,7 @@ The folder layout, file naming, and document format are designed so that AI agen
65
66
  - Each XDR is a small, focused Markdown file (target under 1300 words), covering one decision.
66
67
  - The canonical index per scope and type lists all XDRs with short descriptions, enabling agents to identify relevant records without reading every file.
67
68
  - The root index at `.xdrs/index.md` provides a single entry point for discovery.
68
- - XDR metadata gives agents a first-pass filter: check `Status` first, treating an omitted `Status` as `Active`; then check `Valid`, then `Applied to`, and finally the decision text itself to confirm the decision should be used in the current context.
69
+ - XDR metadata gives agents a first-pass filter: check `Valid` for the convergence date, then check `Applied to`, and finally the decision text itself to confirm the decision should be used in the current context. All documents present in the collection are considered active.
69
70
  - Decisions cross-reference each other by XDR ID rather than duplicating content, keeping individual files concise.
70
71
  - Subject folders reduce the search space when a query maps to a known domain.
71
72
 
@@ -96,6 +97,9 @@ This is especially important for BDRs: because business rules govern decisions t
96
97
  articles/ # optional synthetic views over XDRs, Research, and Skills
97
98
  [number]-[short-title].md
98
99
  assets/
100
+ plans/ # optional ephemeral execution plans
101
+ [number]-[short-title].md
102
+ assets/
99
103
  ```
100
104
 
101
105
  Document types:
@@ -106,6 +110,7 @@ Document types:
106
110
  - **Research** - Exploratory support material used while evaluating or updating a decision. Research captures constraints, findings, options, and proposal tradeoffs, but it is not the source of truth.
107
111
  - **Skills** - Step-by-step procedural guides that can be followed by humans, AI agents, or both. Must comply with Decision Records, but add the execution detail they lack. Skills are not mandatory by themselves unless referenced by an XDR or another policy artifact. A skill may start as a fully manual human procedure and evolve incrementally toward partial or full AI automation without being restructured. Co-located with the XDRs they implement inside `skills/` sub-directories.
108
112
  - **Articles** - Synthetic views that explain concepts or combine information from multiple Decision Records, Research documents, and Skills into a coherent text for a specific topic or audience. Articles are not the source of truth; Decision Records take precedence when there is a conflict. Useful as navigational indexes that link related artifacts around a specific aspect.
113
+ - **Plans** - Ephemeral execution documents that describe a problem, proposed solution, and the approach and activities needed to solve it. Plans have a clear start and end and must be deleted after full implementation. Lasting outputs are captured as Decisions, Skills, Articles, or other artifacts. Co-located with XDRs inside `plans/` sub-directories.
109
114
 
110
115
  See [.xdrs/index.md](.xdrs/index.md) for the full list of active decision records.
111
116
 
@@ -157,9 +162,11 @@ The `lint` command reads `./.xdrs/**` from the given workspace path and checks c
157
162
  - skill numbering uniqueness per `scope/type/subject/skills`
158
163
  - article numbering uniqueness per `scope/type/subject/articles`
159
164
  - research numbering uniqueness per `scope/type/subject/researches`
165
+ - plan numbering uniqueness per `scope/type/subject/plans`
166
+ - plan `Expected end date:` field presence and ISO date format
160
167
  - canonical index presence and link consistency
161
168
  - root index coverage for all discovered canonical indexes
162
- - XDR metadata section placement and `Status` / `Valid` / `Applied to` field format
169
+ - XDR metadata section placement and `Valid` / `Applied to` field format
163
170
  - local image and `assets/` links resolving inside the sibling `assets/` folder for each document
164
171
 
165
172
  Examples:
package/lib/lint.js CHANGED
@@ -21,7 +21,7 @@ const RESERVED_SCOPES = new Set(['_core', '_local']);
21
21
  const NUMBERED_FILE_RE = /^(\d{3,})-([a-z0-9-]+)\.md$/;
22
22
  const NUMBERED_DIR_RE = /^(\d{3,})-([a-z0-9-]+)$/;
23
23
  const REQUIRED_ROOT_INDEX_TEXT = 'XDRs in scopes listed last override the ones listed first';
24
- const SUBJECT_ARTIFACT_DIRS = new Set(['skills', 'articles', 'researches']);
24
+ const SUBJECT_ARTIFACT_DIRS = new Set(['skills', 'articles', 'researches', 'plans']);
25
25
  const RESOURCE_DIR_NAME = 'assets';
26
26
  const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp']);
27
27
 
@@ -206,6 +206,10 @@ function lintSubjectDirectory(xdrsRoot, scopeName, typeName, subjectName, xdrNum
206
206
  artifacts.push(...lintResearchDirectory(xdrsRoot, scopeName, typeName, subjectName, entryPath, errors));
207
207
  continue;
208
208
  }
209
+ if (entry.name === 'plans') {
210
+ artifacts.push(...lintPlansDirectory(xdrsRoot, scopeName, typeName, subjectName, entryPath, errors));
211
+ continue;
212
+ }
209
213
 
210
214
  errors.push(`Unexpected directory under ${scopeName}/${typeName}/${subjectName}: ${toDisplayPath(entryPath)}`);
211
215
  continue;
@@ -277,11 +281,10 @@ function lintXdrMetadata(content, filePath, errors) {
277
281
  start: metadataLine + 1,
278
282
  end: (headingLines.find((lineIndex) => lineIndex > metadataLine) ?? lines.length) - 1
279
283
  };
280
- const statusLineNumbers = findFieldLines(lines, ignoredLines, 'Status:');
281
284
  const appliedLineNumbers = findFieldLines(lines, ignoredLines, 'Applied to:');
282
285
  const validLineNumbers = findFieldLines(lines, ignoredLines, 'Valid:');
283
286
 
284
- if (!metadataRange && (statusLineNumbers.length > 0 || appliedLineNumbers.length > 0 || validLineNumbers.length > 0)) {
287
+ if (!metadataRange && (appliedLineNumbers.length > 0 || validLineNumbers.length > 0)) {
285
288
  errors.push(`XDR metadata fields require a ## Metadata section immediately before Context and Problem Statement: ${toDisplayPath(filePath)}`);
286
289
  return;
287
290
  }
@@ -290,18 +293,13 @@ function lintXdrMetadata(content, filePath, errors) {
290
293
  return;
291
294
  }
292
295
 
293
- const metadataStatus = statusLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
294
296
  const metadataApplied = appliedLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
295
297
  const metadataValid = validLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
296
298
 
297
- if (metadataStatus.length === 0 && metadataApplied.length === 0 && metadataValid.length === 0) {
299
+ if (metadataApplied.length === 0 && metadataValid.length === 0) {
298
300
  errors.push(`XDR metadata section must be omitted when no metadata fields are defined: ${toDisplayPath(filePath)}`);
299
301
  }
300
302
 
301
- if (metadataStatus.length > 1) {
302
- errors.push(`XDR metadata must not repeat Status: ${toDisplayPath(filePath)}`);
303
- }
304
-
305
303
  if (metadataApplied.length > 1) {
306
304
  errors.push(`XDR metadata must not repeat Applied to: ${toDisplayPath(filePath)}`);
307
305
  }
@@ -310,7 +308,7 @@ function lintXdrMetadata(content, filePath, errors) {
310
308
  errors.push(`XDR metadata must not repeat Valid: ${toDisplayPath(filePath)}`);
311
309
  }
312
310
 
313
- for (const lineIndex of [...statusLineNumbers, ...appliedLineNumbers, ...validLineNumbers]) {
311
+ for (const lineIndex of [...appliedLineNumbers, ...validLineNumbers]) {
314
312
  if (!isLineInsideRange(lineIndex, metadataRange)) {
315
313
  errors.push(`XDR metadata fields must be declared inside ## Metadata: ${toDisplayPath(filePath)}`);
316
314
  break;
@@ -326,28 +324,22 @@ function lintXdrMetadata(content, filePath, errors) {
326
324
  if (trimmed === '') {
327
325
  continue;
328
326
  }
329
- const currentFieldOrder = trimmed.startsWith('Status:')
327
+ const currentFieldOrder = trimmed.startsWith('Valid:')
330
328
  ? 0
331
- : trimmed.startsWith('Valid:')
329
+ : trimmed.startsWith('Applied to:')
332
330
  ? 1
333
- : trimmed.startsWith('Applied to:')
334
- ? 2
335
- : -1;
331
+ : -1;
336
332
  if (currentFieldOrder === -1) {
337
- errors.push(`XDR metadata section only supports Status:, Valid:, and Applied to: fields: ${toDisplayPath(filePath)}`);
333
+ errors.push(`XDR metadata section only supports Valid: and Applied to: fields: ${toDisplayPath(filePath)}`);
338
334
  break;
339
335
  }
340
336
  if (currentFieldOrder < previousFieldOrder) {
341
- errors.push(`XDR metadata fields must be ordered as Status:, Valid:, Applied to: ${toDisplayPath(filePath)}`);
337
+ errors.push(`XDR metadata fields must be ordered as Valid:, Applied to: ${toDisplayPath(filePath)}`);
342
338
  break;
343
339
  }
344
340
  previousFieldOrder = currentFieldOrder;
345
341
  }
346
342
 
347
- if (metadataStatus.length === 1) {
348
- lintStatusField(lines[metadataStatus[0]], filePath, errors);
349
- }
350
-
351
343
  if (metadataApplied.length === 1) {
352
344
  const value = lines[metadataApplied[0]].slice('Applied to:'.length).trim();
353
345
  if (value === '') {
@@ -362,32 +354,18 @@ function lintXdrMetadata(content, filePath, errors) {
362
354
  }
363
355
  }
364
356
 
365
- function lintStatusField(line, filePath, errors) {
366
- const value = line.slice('Status:'.length).trim().replace(/\.$/, '');
367
-
368
- if (value !== 'Draft' && value !== 'Active' && value !== 'Deprecated') {
369
- errors.push(`XDR Status: must be Draft, Active, or Deprecated: ${toDisplayPath(filePath)}`);
370
- }
371
- }
372
-
373
357
  function lintValidField(line, filePath, errors) {
374
358
  const value = line.slice('Valid:'.length).trim().replace(/\.$/, '');
375
359
 
376
- const validMatch = value.match(/^(?:from\s+(\d{4}-\d{2}-\d{2})(?:\s+until\s+(\d{4}-\d{2}-\d{2}))?|until\s+(\d{4}-\d{2}-\d{2}))$/);
360
+ const validMatch = value.match(/^from\s+(\d{4}-\d{2}-\d{2})$/);
377
361
  if (!validMatch) {
378
- errors.push(`XDR Valid: must be from YYYY-MM-DD, until YYYY-MM-DD, or from YYYY-MM-DD until YYYY-MM-DD: ${toDisplayPath(filePath)}`);
362
+ errors.push(`XDR Valid: must be from YYYY-MM-DD: ${toDisplayPath(filePath)}`);
379
363
  return;
380
364
  }
381
365
 
382
366
  const fromDate = validMatch[1];
383
- const untilDate = validMatch[2] ?? validMatch[3];
384
- if ((fromDate && !isIsoDate(fromDate)) || (untilDate && !isIsoDate(untilDate))) {
367
+ if (!isIsoDate(fromDate)) {
385
368
  errors.push(`XDR Valid: must use ISO dates in YYYY-MM-DD format: ${toDisplayPath(filePath)}`);
386
- return;
387
- }
388
-
389
- if (fromDate && untilDate && fromDate > untilDate) {
390
- errors.push(`XDR Valid: from date must be on or before until date: ${toDisplayPath(filePath)}`);
391
369
  }
392
370
  }
393
371
 
@@ -541,6 +519,76 @@ function lintResearchDirectory(xdrsRoot, scopeName, typeName, subjectName, resea
541
519
  return artifacts;
542
520
  }
543
521
 
522
+ function lintPlansDirectory(xdrsRoot, scopeName, typeName, subjectName, plansPath, errors) {
523
+ const artifacts = [];
524
+ const planNumbers = new Map();
525
+ const entries = safeReadDir(plansPath, errors, `read plans directory ${scopeName}/${typeName}/${subjectName}/plans`);
526
+
527
+ for (const entry of entries) {
528
+ const entryPath = path.join(plansPath, entry.name);
529
+ if (entry.isDirectory() && entry.name === RESOURCE_DIR_NAME) {
530
+ continue;
531
+ }
532
+
533
+ if (!entry.isFile()) {
534
+ errors.push(`Unexpected directory in plans folder: ${toDisplayPath(entryPath)}`);
535
+ continue;
536
+ }
537
+
538
+ const match = entry.name.match(NUMBERED_FILE_RE);
539
+ if (!match) {
540
+ errors.push(`Invalid plan file name: ${toDisplayPath(entryPath)}`);
541
+ continue;
542
+ }
543
+
544
+ artifacts.push(entryPath);
545
+
546
+ const number = match[1];
547
+ const previous = planNumbers.get(number);
548
+ if (previous) {
549
+ errors.push(`Duplicate plan number ${number} in ${scopeName}/${typeName}/${subjectName}/plans: ${toDisplayPath(previous)} and ${toDisplayPath(entryPath)}`);
550
+ } else {
551
+ planNumbers.set(number, entryPath);
552
+ }
553
+
554
+ if (entry.name !== entry.name.toLowerCase()) {
555
+ errors.push(`Plan file name must be lowercase: ${toDisplayPath(entryPath)}`);
556
+ }
557
+
558
+ const content = fs.readFileSync(entryPath, 'utf8');
559
+ const expectedHeader = `# ${scopeName}-plan-${number}:`;
560
+ const firstLine = firstNonEmptyLine(content);
561
+ if (!firstLine.startsWith(expectedHeader)) {
562
+ errors.push(`Plan title must start with "${expectedHeader}": ${toDisplayPath(entryPath)}`);
563
+ }
564
+
565
+ lintPlanExpectedEndDate(content, entryPath, errors);
566
+ lintDocumentResourceLinks(entryPath, errors);
567
+ }
568
+
569
+ return artifacts;
570
+ }
571
+
572
+ function lintPlanExpectedEndDate(content, filePath, errors) {
573
+ const lines = content.split(/\r?\n/);
574
+ const ignoredLines = findIgnoredMarkdownLines(lines);
575
+ const expectedEndDateLines = findFieldLines(lines, ignoredLines, 'Expected end date:');
576
+
577
+ if (expectedEndDateLines.length === 0) {
578
+ errors.push(`Plan must include an Expected end date: field: ${toDisplayPath(filePath)}`);
579
+ return;
580
+ }
581
+
582
+ if (expectedEndDateLines.length > 1) {
583
+ errors.push(`Plan must not repeat Expected end date: ${toDisplayPath(filePath)}`);
584
+ }
585
+
586
+ const value = lines[expectedEndDateLines[0]].slice('Expected end date:'.length).trim().replace(/\.$/, '');
587
+ if (!isIsoDate(value)) {
588
+ errors.push(`Plan Expected end date: must be a valid ISO date in YYYY-MM-DD format: ${toDisplayPath(filePath)}`);
589
+ }
590
+ }
591
+
544
592
  function lintTypeIndex(indexPath, xdrsRoot, artifacts, errors) {
545
593
  const content = fs.readFileSync(indexPath, 'utf8');
546
594
  const localLinks = parseLocalLinks(content, path.dirname(indexPath));
package/lib/testPrompt.js CHANGED
@@ -231,6 +231,7 @@ async function runJudgePhase({ judgePrompt, commandTemplate, continueFlag, works
231
231
  '',
232
232
  '<INSTRUCTIONS>',
233
233
  'You are evaluating the result of the task you completed in the RUN PHASE.',
234
+ 'Don\'t ask any questions and assume automatically everything because you are running in a testing environment without the possibility of user interaction',
234
235
  'Read files from the workspace directly when you need their contents.',
235
236
  'ALWAYS answer with JSON using the schema specified below, and never include any other text.',
236
237
  'Response schema: {"pass":false,"text":"plain text summary of the evaluation","findings":[{"target":"file","path":"relative/path.ext","line":1,"message":"explanation","assertionRef":"exact relevant phrase from the judge prompt"}]}.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xdrs-core",
3
- "version": "0.13.0",
3
+ "version": "0.14.2",
4
4
  "description": "A standard way to organize Decision Records (XDRs) across scopes, subjects, and teams so that AI agents can reliably query and follow them.",
5
5
  "repository": {
6
6
  "type": "git",