yarramate 0.12.0 → 0.13.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.
package/README.md CHANGED
@@ -17,6 +17,20 @@ whose gaps are found deterministically.
17
17
  > YarraMate is pre-release software. Interfaces may evolve before the first
18
18
  > stable release.
19
19
 
20
+ ## Proven across harnesses
21
+
22
+ The design bet is that the model — not the session — is the state, so any
23
+ agent in any harness can resume the work cold. We tested that adversarially
24
+ on a real product: a Claude Code session worked the design interview all
25
+ day, then an OpenAI Codex session — no shared context, the tool never
26
+ named — resumed it from a ten-line pointer file and the published CLI. It
27
+ answered 63 open design questions, filed two genuine defect reports, and in
28
+ a later session reported that the model "was not merely documentation" — it
29
+ caught an approval-path regression before the release shipped.
30
+
31
+ The full story, with every commit, PR, and release attached:
32
+ [The model is the handover](docs/CASE-STUDY-CROSS-HARNESS.md).
33
+
20
34
  ## Why YarraMate?
21
35
 
22
36
  Architecture documents often drift away from implementation or become tied to
@@ -134,6 +148,7 @@ node dist/cli.js ask .yarramate/workspace.yaml
134
148
  node dist/cli.js ask .yarramate/workspace.yaml "free text about the model"
135
149
  node dist/cli.js ask .yarramate/workspace.yaml --subjects
136
150
  node dist/cli.js ask .yarramate/workspace.yaml --advise "a design question"
151
+ node dist/cli.js ask .yarramate/workspace.yaml --where "compiler"
137
152
  node dist/cli.js check .yarramate/workspace.yaml --json
138
153
  node dist/cli.js reconcile .yarramate/workspace.yaml
139
154
  node dist/cli.js export graph .yarramate/workspace.yaml
@@ -8,7 +8,7 @@ import { deriveChangedSubjects } from './changed.js';
8
8
  import { runCheckCommand } from './check-command.js';
9
9
  import { diagnosticJson, humanDiagnostics, usage, } from './cli-support.js';
10
10
  import { compileWorkspaceWithProfileContext, } from './compiler.js';
11
- import { evaluateEvidenceWorkspace, loadEvidence } from './evidence.js';
11
+ import { evaluateEvidenceWorkspace, loadEvidence, } from './evidence.js';
12
12
  import { evaluateCatalogue, loadQuestionCatalogue, renderInterrogationReport, } from './interrogate-command.js';
13
13
  import { buildNextSubjects, coverageClause, } from './next-command.js';
14
14
  import { conceptKinds, relationshipPolicies, } from './profile.js';
@@ -124,6 +124,7 @@ export function runAskCommand(options, cwd) {
124
124
  let open = false;
125
125
  let kinds = false;
126
126
  let advise = false;
127
+ let where = false;
127
128
  let compare;
128
129
  let changed;
129
130
  let budget;
@@ -157,6 +158,10 @@ export function runAskCommand(options, cwd) {
157
158
  advise = true;
158
159
  continue;
159
160
  }
161
+ if (option === '--where') {
162
+ where = true;
163
+ continue;
164
+ }
160
165
  if (option === '--compare') {
161
166
  const from = options[index + 1];
162
167
  const to = options[index + 2];
@@ -231,6 +236,12 @@ export function runAskCommand(options, cwd) {
231
236
  exclusiveModes > 1 ||
232
237
  (advise && exclusiveModes > 0) ||
233
238
  (advise && query.length === 0) ||
239
+ (where &&
240
+ (exclusiveModes > 0 ||
241
+ advise ||
242
+ changed !== undefined ||
243
+ budget !== undefined ||
244
+ query.length === 0)) ||
234
245
  (query.length > 0 && exclusiveModes > 0) ||
235
246
  (changed !== undefined &&
236
247
  (query.length > 0 || exclusiveModes > 0 || advise)) ||
@@ -638,7 +649,10 @@ export function runAskCommand(options, cwd) {
638
649
  // names a projection file is precise addressing; anything else runs
639
650
  // through free-text seeding, where exact subject ids win.
640
651
  const soleTerm = query.length === 1 ? query[0] : undefined;
641
- const projectionCandidate = soleTerm !== undefined && !advise && existsSync(resolve(cwd, soleTerm))
652
+ const projectionCandidate = soleTerm !== undefined &&
653
+ !advise &&
654
+ !where &&
655
+ existsSync(resolve(cwd, soleTerm))
642
656
  ? resolve(cwd, soleTerm)
643
657
  : undefined;
644
658
  if (projectionCandidate !== undefined &&
@@ -672,6 +686,92 @@ export function runAskCommand(options, cwd) {
672
686
  `List the roster: yarramate ask ${workspacePath} --subjects\n`,
673
687
  };
674
688
  }
689
+ // --where: evidence-backed pointing (ADR 0068). Verified locations for
690
+ // the matched subjects, an explicit list of matched-but-unobserved
691
+ // subjects, and a hand-off note for everything outside the model —
692
+ // authority follows epistemic status, so the routing is stated in the
693
+ // output rather than assumed by the reader.
694
+ if (where) {
695
+ const evidenceDocuments = [];
696
+ for (const path of workspace.evidence) {
697
+ const loaded = loadEvidence({
698
+ path,
699
+ source: readFileSync(resolve(cwd, path), 'utf8'),
700
+ });
701
+ if (!loaded.ok)
702
+ return failed(loaded.diagnostics);
703
+ evidenceDocuments.push(loaded.evidence);
704
+ }
705
+ const subjectOf = (observation) => 'subject' in observation
706
+ ? observation.subject
707
+ : (observation.claim.split('~')[0] ?? observation.claim);
708
+ // Subject- and claim-level observations often share a locator; the
709
+ // pointer is the same either way, so identical entries collapse.
710
+ const entriesBySeed = resolution.seeds.map((seed) => ({
711
+ subject: seed,
712
+ observations: [
713
+ ...new Map(evidenceDocuments
714
+ .flatMap((document) => document.observations
715
+ .filter((observation) => subjectOf(observation) === seed)
716
+ .map((observation) => ({
717
+ uri: observation.evidence.uri,
718
+ result: observation.result,
719
+ provider: document.provider,
720
+ ...(observation.evidence.message === undefined
721
+ ? {}
722
+ : { message: observation.evidence.message }),
723
+ })))
724
+ .map((entry) => [
725
+ `${entry.uri}${entry.result}${entry.provider}${entry.message ?? ''}`,
726
+ entry,
727
+ ])).values(),
728
+ ].sort((left, right) => left.uri.localeCompare(right.uri) ||
729
+ left.result.localeCompare(right.result)),
730
+ }));
731
+ const located = entriesBySeed.filter(({ observations }) => observations.length > 0);
732
+ const unobserved = entriesBySeed
733
+ .filter(({ observations }) => observations.length === 0)
734
+ .map(({ subject }) => subject);
735
+ const note = workspace.evidence.length === 0
736
+ ? 'This workspace declares no evidence overlay, so no location is verified. For code locations, use your search tools; author evidence observations to make locations verifiable.'
737
+ : 'Locations above are verified by evidence overlays. Subjects listed as unobserved are modeled but unlocated. For code outside the model, use your search tools or a code index.';
738
+ const result = {
739
+ format: 'yarramate/ask-result/v1',
740
+ workspace: workspace.id,
741
+ mode: 'where',
742
+ addressing: resolution.addressing,
743
+ topic,
744
+ seeds: resolution.seeds,
745
+ matched: resolution.matched,
746
+ located,
747
+ coverage: { unobserved, note },
748
+ };
749
+ const lines = [
750
+ `Where: "${topic}" — ${plural(resolution.matched, 'concept')} matched` +
751
+ (resolution.matched > resolution.seeds.length
752
+ ? `, seeded from the top ${resolution.seeds.length}`
753
+ : '') +
754
+ `: ${resolution.seeds.join(', ')}`,
755
+ '',
756
+ ];
757
+ for (const entry of located) {
758
+ lines.push(` ${entry.subject}`);
759
+ for (const observation of entry.observations) {
760
+ lines.push(` ${observation.result} ${observation.uri} (${observation.provider})`);
761
+ if (observation.message !== undefined) {
762
+ lines.push(` ${observation.message}`);
763
+ }
764
+ }
765
+ }
766
+ if (located.length === 0) {
767
+ lines.push(' no verified locations');
768
+ }
769
+ if (unobserved.length > 0) {
770
+ lines.push('', ` unobserved — modeled, no evidence: ${unobserved.join(', ')}`);
771
+ }
772
+ lines.push('', note);
773
+ return emit(result, `${lines.join('\n')}\n`);
774
+ }
675
775
  const evaluated = sliceProjection(graph, resolution.seeds, topic, compilation.profileContext);
676
776
  if (!advise) {
677
777
  const result = {
@@ -7,7 +7,7 @@ export interface CliResult {
7
7
  export declare const isMainModule: (moduleUrl: string, entrypoint: string | undefined) => boolean;
8
8
  export declare const packageVersion: string;
9
9
  export declare const versionResult: (binary: string) => CliResult;
10
- export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
10
+ export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where \"<free text>\" | <document-id>#<local-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
11
11
  export declare const diagnosticJson: (diagnostics: unknown) => string;
12
12
  export declare const checkResultJson: (ok: boolean, diagnostics: unknown, counted?: {
13
13
  readonly documents: number;
@@ -23,7 +23,7 @@ export const versionResult = (binary) => ({
23
23
  stdout: `${binary} ${packageVersion}\n`,
24
24
  stderr: '',
25
25
  });
26
- export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
26
+ export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <document-id>#<local-id>] [--catalogue <catalogue.yaml>] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <document-id>#<local-id> ... | <projection.yaml> [--budget <tokens>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where "<free text>" | <document-id>#<local-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml>\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
27
27
  export const diagnosticJson = (diagnostics) => `${JSON.stringify({
28
28
  format: 'yarramate/diagnostic-result/v1',
29
29
  diagnostics,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yarramate",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Tool-neutral semantic architecture engine and guided methodology",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://yarrasys.dev/schema/yarramate-ask-result.schema.json",
4
4
  "title": "YarraMate ask result",
5
- "description": "One envelope for every consumed-now read: orientation, roster, slice, advice, next, open questions, and state comparison, discriminated by mode.",
5
+ "description": "One envelope for every consumed-now read: orientation, roster, slice, advice, verified locations, next, open questions, and state comparison, discriminated by mode.",
6
6
  "type": "object",
7
7
  "required": [
8
8
  "format",
@@ -23,6 +23,7 @@
23
23
  "roster",
24
24
  "slice",
25
25
  "advice",
26
+ "where",
26
27
  "next",
27
28
  "open",
28
29
  "compare",
@@ -363,6 +364,119 @@
363
364
  },
364
365
  "additionalProperties": false
365
366
  },
367
+ {
368
+ "type": "object",
369
+ "required": [
370
+ "mode",
371
+ "addressing",
372
+ "topic",
373
+ "seeds",
374
+ "matched",
375
+ "located",
376
+ "coverage"
377
+ ],
378
+ "properties": {
379
+ "format": true,
380
+ "workspace": true,
381
+ "mode": {
382
+ "const": "where"
383
+ },
384
+ "addressing": {
385
+ "enum": [
386
+ "free-text",
387
+ "subjects"
388
+ ]
389
+ },
390
+ "topic": {
391
+ "type": "string",
392
+ "minLength": 1
393
+ },
394
+ "seeds": {
395
+ "type": "array",
396
+ "items": {
397
+ "type": "string",
398
+ "minLength": 1
399
+ }
400
+ },
401
+ "matched": {
402
+ "type": "integer",
403
+ "minimum": 0
404
+ },
405
+ "located": {
406
+ "type": "array",
407
+ "items": {
408
+ "type": "object",
409
+ "required": [
410
+ "subject",
411
+ "observations"
412
+ ],
413
+ "additionalProperties": false,
414
+ "properties": {
415
+ "subject": {
416
+ "type": "string",
417
+ "minLength": 1
418
+ },
419
+ "observations": {
420
+ "type": "array",
421
+ "minItems": 1,
422
+ "items": {
423
+ "type": "object",
424
+ "required": [
425
+ "uri",
426
+ "result",
427
+ "provider"
428
+ ],
429
+ "additionalProperties": false,
430
+ "properties": {
431
+ "uri": {
432
+ "type": "string",
433
+ "minLength": 1
434
+ },
435
+ "result": {
436
+ "enum": [
437
+ "confirmed",
438
+ "contradicted",
439
+ "unknown",
440
+ "not-observed"
441
+ ]
442
+ },
443
+ "provider": {
444
+ "type": "string",
445
+ "minLength": 1
446
+ },
447
+ "message": {
448
+ "type": "string",
449
+ "minLength": 1
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+ }
456
+ },
457
+ "coverage": {
458
+ "type": "object",
459
+ "required": [
460
+ "unobserved",
461
+ "note"
462
+ ],
463
+ "additionalProperties": false,
464
+ "properties": {
465
+ "unobserved": {
466
+ "type": "array",
467
+ "items": {
468
+ "type": "string",
469
+ "minLength": 1
470
+ }
471
+ },
472
+ "note": {
473
+ "type": "string",
474
+ "minLength": 1
475
+ }
476
+ }
477
+ }
478
+ }
479
+ },
366
480
  {
367
481
  "type": "object",
368
482
  "required": [
@@ -33,7 +33,10 @@ design questions, and the backlog — planned subjects in dependency
33
33
  order. `ask <workspace.yaml> --subjects` lists every concept;
34
34
  `ask <workspace.yaml> --kinds` lists the declarable vocabulary;
35
35
  `ask <workspace.yaml> "<free text>"` returns the model slice matching
36
- your words.
36
+ your words; `ask <workspace.yaml> --where "<free text>"` returns the
37
+ evidence-verified code locations of matching subjects — prefer those
38
+ over searching when the subject is modeled, and use your own search
39
+ tools beyond the coverage boundary the output states.
37
40
 
38
41
  - Existing implementation is the starting point: follow **Discover an
39
42
  existing project**.