gcf-aif-ext 0.5.0 → 0.5.1
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.
- package/README.md +6 -0
- package/extension.json +1 -1
- package/lib/design-check.js +24 -6
- package/package.json +1 -1
- package/profiles/glossary.md +1 -1
- package/profiles/system.md +2 -2
- package/profiles/unit-constraint.md +3 -3
- package/profiles/unit-entity.md +3 -3
- package/profiles/unit-mechanic.md +6 -18
- package/profiles/unit-resource.md +6 -18
- package/profiles/unit-rule.md +3 -3
- package/skills/gcf-card/SKILL.md +3 -2
- package/templates/agents-block.md +1 -2
package/README.md
CHANGED
|
@@ -50,6 +50,12 @@ Updating preserves `gcf/`, `cnlp.config.json` and the pre-commit hook. Run `ai-f
|
|
|
50
50
|
|
|
51
51
|
On Windows, run `extension add` and `extension update` from PowerShell or cmd, not Git Bash: the installer unpacks with `tar`, and Git Bash's GNU tar reads `C:\…` as a remote host (`Cannot connect to C: resolve failed`). The Windows `tar.exe` handles it.
|
|
52
52
|
|
|
53
|
+
### 0.5.1
|
|
54
|
+
|
|
55
|
+
- A provenance record `assumed: q-NNN` must name a record still in `gcf/open-questions.md` (M9). A D2 record lives until its `until:` fires; once the human confirms the value, cite `answer: q-NNN` instead and remove it. After updating, run `ai-factory gcf design check`: every citation of a removed question blocks the commit gate until it is rewritten.
|
|
56
|
+
- An unplayed item's body is frozen, so a word added to the glossary or a removed question is reported there, not blocked.
|
|
57
|
+
- The `AGENTS.md` block has no `##` heading any more: a CNL-P guide is flat. A project that checks `AGENTS.md` with `cnlp check` adds `gcf_context`, `gcf_work`, `gcf_forbidden` and `gcf_skills` to `custom_sections` of its guide profile.
|
|
58
|
+
|
|
53
59
|
### 0.5.0
|
|
54
60
|
|
|
55
61
|
The run layer of the methodology. Update both extensions together — `gcf-harness-aif-ext` 0.6.0 requires this core — and run `ai-factory gcf init` to refresh the agent block in `AGENTS.md`. New commands:
|
package/extension.json
CHANGED
package/lib/design-check.js
CHANGED
|
@@ -121,12 +121,14 @@ function itemsIn(text, key) {
|
|
|
121
121
|
export const recordsIn = (text, key) =>
|
|
122
122
|
readRecords(itemsIn(text, key)).records.map((r) => r.values);
|
|
123
123
|
|
|
124
|
-
/**
|
|
124
|
+
/** open-questions.md: every record id, every `blocks:` reference, the D1 ones per blocked id. */
|
|
125
125
|
export function questionBlocks(text) {
|
|
126
126
|
/** @type {Map<string, string[]>} */
|
|
127
127
|
const d1 = new Map();
|
|
128
128
|
const refs = [];
|
|
129
|
-
|
|
129
|
+
const src = String(text ?? '');
|
|
130
|
+
const qids = new Set([...src.matchAll(/^\s*- id:\s*(\S+)/gm)].map((m) => m[1]));
|
|
131
|
+
for (const rec of src.split(/\n(?=- id:)/)) {
|
|
130
132
|
const qid = rec.match(/^- id:\s*(\S+)/)?.[1];
|
|
131
133
|
const ids = listOf(rec.match(/^\s+blocks:\s*(.+)$/m)?.[1] ?? '');
|
|
132
134
|
if (!qid || ids === 'TBD' || !ids.length) continue;
|
|
@@ -135,7 +137,7 @@ export function questionBlocks(text) {
|
|
|
135
137
|
for (const id of ids) d1.set(id, [...(d1.get(id) ?? []), qid]);
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
return { d1, refs };
|
|
140
|
+
return { d1, refs, qids };
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
/** Everything outside a unit that its references resolve against. */
|
|
@@ -296,7 +298,15 @@ function recordProblem(r, ctx) {
|
|
|
296
298
|
}
|
|
297
299
|
|
|
298
300
|
if (r.answer) return /^(q-\d+|manual)$/.test(r.answer) ? null : 'answer is q-NNN or manual';
|
|
299
|
-
if (r.assumed)
|
|
301
|
+
if (r.assumed) {
|
|
302
|
+
if (!/^q-\d+$/.test(r.assumed)) return 'assumed is q-NNN';
|
|
303
|
+
|
|
304
|
+
// The D2 record is what the readset and the human's skim list see: it outlives its citation.
|
|
305
|
+
return ctx.questions.qids.has(r.assumed)
|
|
306
|
+
? null
|
|
307
|
+
: `assumed: ${r.assumed} is not in open-questions.md - a D2 record stays until its ` +
|
|
308
|
+
`until: fires; once the human confirms the value, cite answer: ${r.assumed} instead`;
|
|
309
|
+
}
|
|
300
310
|
|
|
301
311
|
return 'a record carries src + quote, answer, or assumed';
|
|
302
312
|
}
|
|
@@ -326,6 +336,9 @@ function uncovered(values, records) {
|
|
|
326
336
|
export const isDrift = (problem) =>
|
|
327
337
|
/^(quote is not verbatim|GDD#\S+ is not an anchor)/.test(problem ?? '');
|
|
328
338
|
|
|
339
|
+
/** The D2 record an `assumed:` cites left open-questions.md. */
|
|
340
|
+
const isGone = (problem) => /^assumed: q-\d+ is not in open-questions/.test(problem ?? '');
|
|
341
|
+
|
|
329
342
|
/** M9: provenance records are well formed, quotes verbatim, every GDD-sourced slot backed. */
|
|
330
343
|
function provenanceIssues(u, values, ctx) {
|
|
331
344
|
const records = provenanceOf(u.body);
|
|
@@ -446,11 +459,16 @@ async function checkItem(item, ctx, ledger) {
|
|
|
446
459
|
const values = slotValues(item.body, profile).filter((v) => !OPERATOR_BLOCKS.includes(v.block));
|
|
447
460
|
for (const v of values.filter((x) => isTbd(x.value)))
|
|
448
461
|
add('M1', v.line, `a unit in work carries no TBD: ${v.block}`);
|
|
449
|
-
|
|
462
|
+
// An unplayed body is frozen (§5.4): a later glossary word or unit, or a gone question, cannot
|
|
463
|
+
// be fixed there, only reported until a tune or a kill takes the item back.
|
|
464
|
+
const frozen = item.data.status === 'unplayed' ? 'report' : 'block';
|
|
465
|
+
for (const [c, line, m] of valueIssues(values, ctx)) add(c, line, m, frozen);
|
|
450
466
|
for (const r of provenanceOf(item.body)) {
|
|
451
467
|
const problem = recordProblem(r, ctx);
|
|
452
468
|
// An item's quotes go stale when the GDD moves on: that is a D1 for the human, not a gate.
|
|
453
|
-
|
|
469
|
+
// A gone question is outside the frozen body too; a malformed record was malformed at close.
|
|
470
|
+
const sev = isDrift(problem) ? 'report' : isGone(problem) ? frozen : 'block';
|
|
471
|
+
if (problem) add('M9', r.line, problem, sev);
|
|
454
472
|
}
|
|
455
473
|
|
|
456
474
|
return issues;
|
package/package.json
CHANGED
package/profiles/glossary.md
CHANGED
|
@@ -33,5 +33,5 @@ custom_sections:
|
|
|
33
33
|
- none: a block that is not listed above belongs to a unit
|
|
34
34
|
|
|
35
35
|
enforcement:
|
|
36
|
-
- `ai-factory gcf design check` refuses a forbidden synonym in gcf/design/ and in a
|
|
36
|
+
- `ai-factory gcf design check` refuses a forbidden synonym in gcf/design/ and in a work item (M4); an unplayed item's frozen body only reports it
|
|
37
37
|
- quoted text is data: a GDD quote keeps the designer's own word
|
package/profiles/system.md
CHANGED
|
@@ -41,7 +41,7 @@ sections:
|
|
|
41
41
|
- key: constraints
|
|
42
42
|
form: bullet-list
|
|
43
43
|
required: yes
|
|
44
|
-
note: negative constraints and invariants accumulated from
|
|
44
|
+
note: negative constraints and invariants accumulated from work items and hard implementations
|
|
45
45
|
|
|
46
46
|
- key: open
|
|
47
47
|
form: bullet-list
|
|
@@ -49,7 +49,7 @@ sections:
|
|
|
49
49
|
note: lines carrying a live "[until: ...]" annotation, moved here by collapse
|
|
50
50
|
|
|
51
51
|
custom_sections:
|
|
52
|
-
- none: a fact that fits no block above belongs to code or to a
|
|
52
|
+
- none: a fact that fits no block above belongs to code or to a work item, not here
|
|
53
53
|
|
|
54
54
|
enforcement:
|
|
55
55
|
- `npx --yes cnlp-kit check`, over the files a `cnlp.config.json` corpus entry maps to this profile
|
|
@@ -8,10 +8,10 @@ format: cnlp-format.md
|
|
|
8
8
|
mood: declarative
|
|
9
9
|
|
|
10
10
|
headings:
|
|
11
|
-
- none: the body is flat; the `## <id>` line and the header fields above the blocks name the unit
|
|
11
|
+
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in work/ the frontmatter does
|
|
12
12
|
|
|
13
13
|
frontmatter_fields:
|
|
14
|
-
- none:
|
|
14
|
+
- none: in design/ the header lives above the blocks; in work/ the work item schema holds the frontmatter
|
|
15
15
|
|
|
16
16
|
lexicon_exempt:
|
|
17
17
|
- none: every block is read when the constraint is planned and measured
|
|
@@ -48,5 +48,5 @@ custom_sections:
|
|
|
48
48
|
- none: a block that is not listed above is prose looking for a home
|
|
49
49
|
|
|
50
50
|
enforcement:
|
|
51
|
-
- `ai-factory gcf design check`, over the units in gcf/design/
|
|
51
|
+
- `ai-factory gcf design check`, over the units in gcf/design/ and the items in gcf/work/
|
|
52
52
|
- the gcf pre-commit hook runs the same check and refuses a commit with a blocking finding
|
package/profiles/unit-entity.md
CHANGED
|
@@ -8,10 +8,10 @@ format: cnlp-format.md
|
|
|
8
8
|
mood: declarative
|
|
9
9
|
|
|
10
10
|
headings:
|
|
11
|
-
- none: the body is flat; the `## <id>` line and the header fields above the blocks name the unit
|
|
11
|
+
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in work/ the frontmatter does
|
|
12
12
|
|
|
13
13
|
frontmatter_fields:
|
|
14
|
-
- none:
|
|
14
|
+
- none: in design/ the header lives above the blocks; in work/ the work item schema holds the frontmatter
|
|
15
15
|
|
|
16
16
|
lexicon_exempt:
|
|
17
17
|
- none: every block is read when the entity is planned and coded
|
|
@@ -44,5 +44,5 @@ custom_sections:
|
|
|
44
44
|
- none: a block that is not listed above is prose looking for a home
|
|
45
45
|
|
|
46
46
|
enforcement:
|
|
47
|
-
- `ai-factory gcf design check`, over the units in gcf/design/
|
|
47
|
+
- `ai-factory gcf design check`, over the units in gcf/design/ and the items in gcf/work/
|
|
48
48
|
- the gcf pre-commit hook runs the same check and refuses a commit with a blocking finding
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: unit-mechanic
|
|
3
|
-
description: The CNL-P profile of a GCF design unit of type mechanic — one body for its section in design/<system>.md and for its
|
|
3
|
+
description: The CNL-P profile of a GCF design unit of type mechanic — one body for its section in design/<system>.md and for its work item in work/<id>.md.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
format: cnlp-format.md
|
|
@@ -8,22 +8,10 @@ format: cnlp-format.md
|
|
|
8
8
|
mood: declarative
|
|
9
9
|
|
|
10
10
|
headings:
|
|
11
|
-
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in
|
|
11
|
+
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in work/ the frontmatter does
|
|
12
12
|
|
|
13
13
|
frontmatter_fields:
|
|
14
|
-
- schema
|
|
15
|
-
- id
|
|
16
|
-
- type
|
|
17
|
-
- title
|
|
18
|
-
- status
|
|
19
|
-
- system
|
|
20
|
-
- depends
|
|
21
|
-
- pillars
|
|
22
|
-
- source
|
|
23
|
-
- reopens
|
|
24
|
-
- tune_count
|
|
25
|
-
- built_at
|
|
26
|
-
- created
|
|
14
|
+
- none: in design/ the header lives above the blocks; in work/ the work item schema holds the frontmatter
|
|
27
15
|
|
|
28
16
|
lexicon_exempt:
|
|
29
17
|
- none: every block is read when the unit is planned, built or played
|
|
@@ -69,12 +57,12 @@ sections:
|
|
|
69
57
|
- key: contract
|
|
70
58
|
form: bullet-list
|
|
71
59
|
required: yes
|
|
72
|
-
note:
|
|
60
|
+
note: work stage, absent in design/ - paths and entry points, never member lists or values; an architecture rule is a constraint
|
|
73
61
|
|
|
74
62
|
- key: interactions
|
|
75
63
|
form: bullet-list
|
|
76
64
|
required: yes
|
|
77
|
-
note:
|
|
65
|
+
note: work stage, absent in design/ - "<other id>: how the two cross", one line per crossing
|
|
78
66
|
|
|
79
67
|
- key: constraints
|
|
80
68
|
form: bullet-list
|
|
@@ -107,5 +95,5 @@ custom_sections:
|
|
|
107
95
|
- none: a block that is not listed above is prose looking for a home
|
|
108
96
|
|
|
109
97
|
enforcement:
|
|
110
|
-
- `ai-factory gcf design check`, over the units in gcf/design/ and the
|
|
98
|
+
- `ai-factory gcf design check`, over the units in gcf/design/ and the items in gcf/work/
|
|
111
99
|
- the gcf pre-commit hook runs the same check and refuses a commit with a blocking finding
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: unit-resource
|
|
3
|
-
description: The CNL-P profile of a GCF design unit of type resource — an economy resource with its sources and sinks, in design/<system>.md and as a
|
|
3
|
+
description: The CNL-P profile of a GCF design unit of type resource — an economy resource with its sources and sinks, in design/<system>.md and as a work item.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
format: cnlp-format.md
|
|
@@ -8,22 +8,10 @@ format: cnlp-format.md
|
|
|
8
8
|
mood: declarative
|
|
9
9
|
|
|
10
10
|
headings:
|
|
11
|
-
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in
|
|
11
|
+
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in work/ the frontmatter does
|
|
12
12
|
|
|
13
13
|
frontmatter_fields:
|
|
14
|
-
- schema
|
|
15
|
-
- id
|
|
16
|
-
- type
|
|
17
|
-
- title
|
|
18
|
-
- status
|
|
19
|
-
- system
|
|
20
|
-
- depends
|
|
21
|
-
- pillars
|
|
22
|
-
- source
|
|
23
|
-
- reopens
|
|
24
|
-
- tune_count
|
|
25
|
-
- built_at
|
|
26
|
-
- created
|
|
14
|
+
- none: in design/ the header lives above the blocks; in work/ the work item schema holds the frontmatter
|
|
27
15
|
|
|
28
16
|
lexicon_exempt:
|
|
29
17
|
- none: every block is read when the unit is planned, built or played
|
|
@@ -49,12 +37,12 @@ sections:
|
|
|
49
37
|
- key: contract
|
|
50
38
|
form: bullet-list
|
|
51
39
|
required: yes
|
|
52
|
-
note:
|
|
40
|
+
note: work stage, absent in design/ - paths and entry points, never member lists or values
|
|
53
41
|
|
|
54
42
|
- key: interactions
|
|
55
43
|
form: bullet-list
|
|
56
44
|
required: yes
|
|
57
|
-
note:
|
|
45
|
+
note: work stage, absent in design/ - "<other id>: how the two cross", one line per crossing
|
|
58
46
|
|
|
59
47
|
- key: constraints
|
|
60
48
|
form: bullet-list
|
|
@@ -87,5 +75,5 @@ custom_sections:
|
|
|
87
75
|
- none: a block that is not listed above is prose looking for a home
|
|
88
76
|
|
|
89
77
|
enforcement:
|
|
90
|
-
- `ai-factory gcf design check`, over the units in gcf/design/ and the
|
|
78
|
+
- `ai-factory gcf design check`, over the units in gcf/design/ and the items in gcf/work/
|
|
91
79
|
- the gcf pre-commit hook runs the same check and refuses a commit with a blocking finding
|
package/profiles/unit-rule.md
CHANGED
|
@@ -8,10 +8,10 @@ format: cnlp-format.md
|
|
|
8
8
|
mood: declarative
|
|
9
9
|
|
|
10
10
|
headings:
|
|
11
|
-
- none: the body is flat; the `## <id>` line and the header fields above the blocks name the unit
|
|
11
|
+
- none: the body is flat; in design/ the `## <id>` line and the header fields above the blocks name the unit, in work/ the frontmatter does
|
|
12
12
|
|
|
13
13
|
frontmatter_fields:
|
|
14
|
-
- none:
|
|
14
|
+
- none: in design/ the header lives above the blocks; in work/ the work item schema holds the frontmatter
|
|
15
15
|
|
|
16
16
|
lexicon_exempt:
|
|
17
17
|
- none: every block is read when the rule is planned and tested
|
|
@@ -48,5 +48,5 @@ custom_sections:
|
|
|
48
48
|
- none: a block that is not listed above is prose looking for a home
|
|
49
49
|
|
|
50
50
|
enforcement:
|
|
51
|
-
- `ai-factory gcf design check`, over the units in gcf/design/
|
|
51
|
+
- `ai-factory gcf design check`, over the units in gcf/design/ and the items in gcf/work/
|
|
52
52
|
- the gcf pre-commit hook runs the same check and refuses a commit with a blocking finding
|
package/skills/gcf-card/SKILL.md
CHANGED
|
@@ -23,10 +23,11 @@ forbidden_behaviors:
|
|
|
23
23
|
- do not put `until:` in the frontmatter: it is a line annotation inside slots
|
|
24
24
|
- do not move a section, edit the backlog or write `status:` by hand: `ai-factory gcf take`, `item new`, `done`, `drop` and the item moves own those
|
|
25
25
|
- do not reuse an id: an ended id stays ended; rework gets a new id with `reopens: <old id>`
|
|
26
|
+
- do not remove a D2 record cited as `assumed: q-NNN`: it stays in `gcf/open-questions.md` until its `until:` fires; when the human confirms the value earlier, rewrite each citation to `answer: q-NNN` first
|
|
26
27
|
|
|
27
28
|
outputs:
|
|
28
29
|
- each answered slot gets a provenance record `- slot: <block>` with `answer: manual`, or `answer: q-NNN` when it closes a question
|
|
29
|
-
- a design-unit item body carries every block of its type
|
|
30
|
+
- a design-unit item body carries every block of its type; a mechanic or resource item adds `contract:` (paths and entry points) and `interactions:` (`<other id>: how the two cross`, or `- none: <why>`)
|
|
30
31
|
- every item carries a `live:` delta before it ends: what it adds, modifies or removes in `gcf/LIVE.md`, or `none: <why>`
|
|
31
32
|
|
|
32
33
|
workflow:
|
|
@@ -44,7 +45,7 @@ workflow:
|
|
|
44
45
|
12. write each answer into the unit in place, with its `answer:` provenance record
|
|
45
46
|
13. run `ai-factory gcf design check --json` until the unit's entry in `units` reads `ready: true`, then commit the answered unit
|
|
46
47
|
14. run `ai-factory gcf take <id>` for one unit, or `ai-factory gcf take <id> <id> --feature <feature-id>` to group several under a feature; it writes `gcf/work/<id>.md` and removes the sections and backlog lines in one step
|
|
47
|
-
15. in each
|
|
48
|
+
15. in each mechanic or resource item write `contract:` from the code tree and `interactions:` from the units and items that write the same state; a soft unit whose human wants no playtest gets `gate: auto` - it will close as unplayed
|
|
48
49
|
16. write the item's `live:` delta (a feature's children keep `none: parent`; the feature writes the capability), run `ai-factory gcf design check`, and commit
|
|
49
50
|
17. report the item paths, each item's gate, and for a verdict item the one question the playtest will answer
|
|
50
51
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
## Game Context Framework (from gcf-aif-ext)
|
|
2
|
-
|
|
3
1
|
gcf_context:
|
|
4
2
|
- the game's design and its work live in `gcf/`, and the `ai-factory gcf` commands and the gcf skills change them
|
|
5
3
|
- read `gcf/INDEX.md` before anything else under `gcf/`: it lists every subsystem, design unit and work item
|
|
@@ -16,6 +14,7 @@ gcf_work:
|
|
|
16
14
|
- work that cannot go on: run `ai-factory gcf block <id> --reason "<why or the question>"`
|
|
17
15
|
- in a worktree on branch `work/<id>` change no `gcf/` file but the item's `live:`, commit all, then run `ai-factory gcf verify <id> --mark`: `ai-factory gcf integrate` in the main checkout merges it and records the move
|
|
18
16
|
- a design question only the human can answer becomes a D1 record in `gcf/open-questions.md`
|
|
17
|
+
- a word added to a `not:` of `gcf/glossary.md` leaves `gcf/design/` and every item but an unplayed one in the same commit: `ai-factory gcf design check` names each hit as M4
|
|
19
18
|
- the human plays from `ai-factory gcf playtest session`; each free note from that play goes to `ai-factory gcf inbox add --source playtest "<note>"`
|
|
20
19
|
- a release item carries `version:` and `channel:` (`item new <id> --type release --release <v> --channel <c>`): its end writes the `release:` block of `gcf/LIVE.md`
|
|
21
20
|
- `item new` and `take` refuse a type the current phase does not take: run `ai-factory gcf phase` and bring the refusal to the human
|