Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: "Test Taxonomy And Fixture Drift"
legend: "PROCESS"
cycle: "0037-test-taxonomy-and-fixture-drift"
source_backlog: "docs/method/backlog/bad-code/PROCESS_test-taxonomy-and-fixture-drift.md"
---

# Test Taxonomy And Fixture Drift

Source backlog item: `docs/method/backlog/bad-code/PROCESS_test-taxonomy-and-fixture-drift.md`
Legend: PROCESS

## Sponsors

- Human: Backlog operator
- Agent: Implementation agent

## Hill

The committed test suite proves the live METHOD legend taxonomy used by
this repo, and any remaining non-doctrine fixture is explicitly named as
a serialization or compatibility case rather than silently looking like
current process truth.

## Playback Questions

### Human

- [ ] Does `method pull` preserve live legends in scaffolded design docs
instead of carrying obsolete fixture taxonomy?
- [ ] Does `method status` report legend health using the live repo
legends rather than stale historical codes?

### Agent

- [ ] Does design-doc frontmatter YAML-escape raw legend scalar
compatibility text instead of letting it masquerade as live
taxonomy?
- [ ] Does `shipSync()` stay idempotent when the closed-cycle fixtures
use live repo legends instead of stale feature labels?

## Accessibility and Assistive Reading

- Linear truth / reduced-complexity posture: test names and fixture text
should state whether they are doctrine fixtures or compatibility
fixtures, so a linear read does not require inferred intent.
- Non-visual or alternate-reading expectations: avoid relying on
filename prefix folklore alone; expectations should be readable from
the test body and the rendered markdown under test.

## Localization and Directionality

- Locale / wording / formatting assumptions: legend codes and frontmatter
keys remain ASCII tokens; the cleanup should not introduce
locale-sensitive casing or formatting behavior.
- Logical direction / layout assumptions: no UI layout changes are in
scope; this cycle is about deterministic repo text fixtures and their
semantics.

## Agent Inspectability and Explainability

- What must be explicit and deterministic for agents: whether a fixture
is meant to reflect current repo taxonomy or a bounded serializer /
compatibility edge case.
- What must be attributable, evidenced, or governed: each remaining
non-doctrine value should be justified by the test title or
surrounding expectation rather than surviving as unexplained drift.

## Non-goals

- [ ] Expanding the repo's live legend set beyond `PROCESS` and `SYNTH`.
- [ ] Rewriting historical design or retro documents outside the active
test suite.
- [ ] Changing runtime legend parsing rules unless the fixture cleanup
proves a real code defect.

## Backlog Context

Several tests still seed obsolete legend codes like `PROTO`, `VIZ`,
`TUI`, and `FEAT`, and they create markdown fixtures that do not follow
the current frontmatter expectations. The committed docs suite, README,
and backlog conventions now claim a tighter live taxonomy than the tests
exercise.

That makes the suite partially validate an older METHOD than the one the
repo documents. Fixtures should either reflect the current doctrine or
be clearly marked as compatibility cases rather than silent drift.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: "Test Taxonomy And Fixture Drift"
cycle: "0037-test-taxonomy-and-fixture-drift"
design_doc: "docs/design/0037-test-taxonomy-and-fixture-drift/test-taxonomy-and-fixture-drift.md"
outcome: hill-met
drift_check: yes
---

# Test Taxonomy And Fixture Drift Retro

## Summary

Updated ordinary test fixtures to use the live repo legends
(`PROCESS`, `SYNTH`, or none) instead of obsolete `PROTO`, `VIZ`,
`TUI`, and `FEAT` examples. The remaining odd legend case is now
explicitly framed as raw scalar compatibility coverage rather than
silent doctrine drift.

The cycle also aligned the packet playback questions to concrete test
descriptions, so close-time drift now reports exact evidence instead of
generic intent with no matching tests.

## Playback Witness

- See `docs/method/retro/0037-test-taxonomy-and-fixture-drift/witness/verification.md`.
- Close-time witness captured `npm test` with 183 passing tests and
reported `No playback-question drift found.`

## Drift

- None recorded at close.

## New Debt

- None recorded.

## Cool Ideas

- None recorded.

## Backlog Maintenance

- Backlog maintenance deferred to regular triage; closure remains valid because the cycle hill was met without requiring repo-wide inbox or graveyard work.
- [ ] Inbox processed
- [x] Priorities reviewed
- [ ] Dead work buried or merged
Comment thread
flyingrobots marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: "Verification Witness for Cycle 37"
---

# Verification Witness for Cycle 37

This witness proves that `Test Taxonomy And Fixture Drift` now carries the required
behavior and adheres to the repo invariants.

## Test Results

```text

> @flyingrobots/method@1.0.0 test
> vitest run --config vitest.config.ts


RUN v4.1.2 .


Test Files 16 passed (16)
Tests 183 passed (183)
Start at 16:37:37
Duration 1.17s (transform 1.10s, setup 0ms, import 3.52s, tests 2.70s, environment 1ms)


```

## Drift Results

```text
No playback-question drift found.
Scanned 1 active cycle, 4 playback questions, 196 test descriptions.
Search basis: exact normalized match in tests/**/*.test.* and tests/**/*.spec.* descriptions.

```

## Manual Verification

- [x] Automated capture completed successfully.
8 changes: 4 additions & 4 deletions tests/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ describe('Method API', () => {
initWorkspace(root);
const workspace = new Workspace(root);

const path = workspace.captureIdea('Test idea', 'PROTO', 'My Title');
expect(path).toContain('PROTO_my-title.md');
const path = workspace.captureIdea('Test idea', 'PROCESS', 'My Title');
expect(path).toContain('PROCESS_my-title.md');

const statusBefore = workspace.status();
expect(statusBefore.backlog.inbox.length).toBe(1);
expect(statusBefore.backlog.inbox[0].stem).toBe('PROTO_my-title');
expect(statusBefore.backlog.inbox[0].stem).toBe('PROCESS_my-title');

const cycle = workspace.pullItem('PROTO_my-title');
const cycle = workspace.pullItem('PROCESS_my-title');
expect(cycle.name).toMatch(/^0001-my-title$/);

const statusAfter = workspace.status();
Expand Down
34 changes: 21 additions & 13 deletions tests/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ describe('method CLI', () => {
const stdout = new MemoryWriter();

const exitCode = await runCli(
['inbox', 'What if Method had a CLI?', '--legend', 'PROTO'],
['inbox', 'What if Method had a CLI?', '--legend', 'PROCESS'],
{ cwd: root, stdout, stderr: new MemoryWriter() },
);

expect(exitCode).toBe(0);
expect(stdout.output).toContain('Captured');
expect(readFile(root, 'docs/method/backlog/inbox/PROTO_what-if-method-had-a-cli.md'))
expect(readFile(root, 'docs/method/backlog/inbox/PROCESS_what-if-method-had-a-cli.md'))
.toContain('# What if Method had a CLI?');
});

Expand All @@ -96,17 +96,17 @@ describe('method CLI', () => {
expectFile(root, 'docs/method/backlog/inbox/backfill-the-missing-inbox-lane.md');
});

it('Does `method pull` create a design doc that already includes required frontmatter fields like `title`, `legend`, `cycle`, and `source_backlog`?', async () => {
it('Does `method pull` preserve live legends in scaffolded design docs instead of carrying obsolete fixture taxonomy?', async () => {
const root = createTempRoot();
await runCli(['init'], { cwd: root, stdout: new MemoryWriter(), stderr: new MemoryWriter() });
writeFileSync(
join(root, 'docs/method/backlog/asap/PROTO_strand-lifecycle.md'),
join(root, 'docs/method/backlog/asap/PROCESS_strand-lifecycle.md'),
'# Strand Lifecycle\n\nMechanical state transitions for strands.\n',
'utf8',
);

const stdout = new MemoryWriter();
const exitCode = await runCli(['pull', 'PROTO_strand-lifecycle'], {
const exitCode = await runCli(['pull', 'PROCESS_strand-lifecycle'], {
cwd: root,
stdout,
stderr: new MemoryWriter(),
Expand All @@ -118,10 +118,10 @@ describe('method CLI', () => {
const designDoc = readFile(root, 'docs/design/0001-strand-lifecycle/strand-lifecycle.md');
expect(designDoc).toMatch(/^---\n[\s\S]+?\n---\n/u);
expect(designDoc).toMatch(/^title:\s+"Strand Lifecycle"$/mu);
expect(designDoc).toMatch(/^legend:\s+"PROTO"$/mu);
expect(designDoc).toMatch(/^legend:\s+"PROCESS"$/mu);
expect(designDoc).toMatch(/^cycle:\s+"0001-strand-lifecycle"$/mu);
expect(designDoc).toMatch(/^source_backlog:\s+"docs\/method\/backlog\/asap\/PROTO_strand-lifecycle\.md"$/mu);
expect(designDoc).toContain('Legend: PROTO');
expect(designDoc).toMatch(/^source_backlog:\s+"docs\/method\/backlog\/asap\/PROCESS_strand-lifecycle\.md"$/mu);
expect(designDoc).toContain('Legend: PROCESS');
expect(designDoc).toContain('- Human: Backlog operator');
expect(designDoc).toContain('- Agent: Implementation agent');
expect(designDoc).toContain('Mechanical state transitions for strands.');
Expand Down Expand Up @@ -234,14 +234,18 @@ describe('method CLI', () => {
expect(retroDoc).not.toContain('Outcome: TBD');
});

it('shows backlog, active cycles, and legend health in status', async () => {
it('Does `method status` report legend health using the live repo legends rather than stale historical codes?', async () => {
Comment thread
flyingrobots marked this conversation as resolved.
const root = createTempRoot();
await runCli(['init'], { cwd: root, stdout: new MemoryWriter(), stderr: new MemoryWriter() });
writeFileSync(join(root, 'docs/method/backlog/inbox/VIZ_braille.md'), '# Braille\n\nIdea\n', 'utf8');
writeFileSync(
join(root, 'docs/method/backlog/inbox/SYNTH_braille.md'),
'# Braille\n\nIdea\n',
'utf8',
);
mkdirSync(join(root, 'docs/design/0001-method-cli'), { recursive: true });
writeFileSync(
join(root, 'docs/design/0001-method-cli/method-cli.md'),
'# Method CLI\n\nLegend: TUI\n\n## Hill\n\nTBD\n',
'# Method CLI\n\nLegend: PROCESS\n\n## Hill\n\nTBD\n',
'utf8',
);

Expand All @@ -251,8 +255,12 @@ describe('method CLI', () => {
expect(exitCode).toBe(0);
expect(stdout.output).toContain('Backlog');
expect(stdout.output).toContain('0001-method-cli');
expect(stdout.output).toContain('VIZ');
expect(stdout.output).toContain('TUI');
expect(stdout.output).toContain('SYNTH');
expect(stdout.output).toContain('PROCESS');
expect(stdout.output).not.toContain('PROTO');
expect(stdout.output).not.toContain('FEAT');
expect(stdout.output).not.toContain('VIZ');
expect(stdout.output).not.toContain('TUI');
});

it('shows status for a clone-like workspace even when empty lane directories are absent', async () => {
Expand Down
8 changes: 4 additions & 4 deletions tests/exec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ describe('Async Exec', () => {
initWorkspace(root);
const workspace = new Workspace(root);

workspace.captureIdea('Test Idea', 'FEAT', 'Async Test');
workspace.pullItem('FEAT_async-test');
workspace.captureIdea('Test Idea', 'PROCESS', 'Async Test');
workspace.pullItem('PROCESS_async-test');

const result = workspace.captureWitness('0001-async-test');
expect(result).toBeInstanceOf(Promise);
Expand All @@ -50,8 +50,8 @@ describe('Async Exec', () => {
initWorkspace(root);
const workspace = new Workspace(root);

workspace.captureIdea('Test Idea', 'FEAT', 'Close Test');
workspace.pullItem('FEAT_close-test');
workspace.captureIdea('Test Idea', 'PROCESS', 'Close Test');
workspace.pullItem('PROCESS_close-test');

const result = workspace.closeCycle('0001-close-test', true, 'hill-met');
expect(result).toBeInstanceOf(Promise);
Expand Down
18 changes: 9 additions & 9 deletions tests/github-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ describe('GitHub Adapter Two-way Sync', () => {
const workspace = new Workspace(root);

// Create item with existing ID
workspace.captureIdea('Local Title', 'FEAT', 'My Item');
const itemPath = 'docs/method/backlog/inbox/FEAT_my-item.md';
workspace.captureIdea('Local Title', 'PROCESS', 'My Item');
const itemPath = 'docs/method/backlog/inbox/PROCESS_my-item.md';
workspace.updateFrontmatter(itemPath, { github_issue_id: '42' });

// Mock GitHub PATCH
Expand Down Expand Up @@ -73,8 +73,8 @@ describe('GitHub Adapter Two-way Sync', () => {
const workspace = new Workspace(root);

// Create item with existing ID
workspace.captureIdea('Local Title', 'FEAT', 'My Item');
const itemPath = 'docs/method/backlog/inbox/FEAT_my-item.md';
workspace.captureIdea('Local Title', 'PROCESS', 'My Item');
const itemPath = 'docs/method/backlog/inbox/PROCESS_my-item.md';
workspace.updateFrontmatter(itemPath, { github_issue_id: '42' });

// Mock GitHub GETs (Issue and Comments)
Expand Down Expand Up @@ -130,8 +130,8 @@ describe('GitHub Adapter Two-way Sync', () => {
const workspace = new Workspace(root);

// Create item with existing ID
workspace.captureIdea('Closed Item', 'FEAT', 'Closed');
const itemPath = 'docs/method/backlog/inbox/FEAT_closed.md';
workspace.captureIdea('Closed Item', 'PROCESS', 'Closed');
const itemPath = 'docs/method/backlog/inbox/PROCESS_closed.md';
workspace.updateFrontmatter(itemPath, { github_issue_id: '99' });

// Mock GitHub GETs (Closed state)
Expand Down Expand Up @@ -165,12 +165,12 @@ describe('GitHub Adapter Two-way Sync', () => {
await adapter.pullBacklog();

// Verify file was moved to graveyard
const graveyardPath = join(root, 'docs/method/graveyard/FEAT_closed.md');
const inboxPath = join(root, 'docs/method/backlog/inbox/FEAT_closed.md');
const graveyardPath = join(root, 'docs/method/graveyard/PROCESS_closed.md');
const inboxPath = join(root, 'docs/method/backlog/inbox/PROCESS_closed.md');

expect(existsSync(graveyardPath), 'file should exist in graveyard').toBe(true);
expect(existsSync(inboxPath), 'file should no longer exist in inbox').toBe(false);
expect(readFileSync(graveyardPath, 'utf8')).toContain('Closed Item');
expect(workspace.readFrontmatter('docs/method/graveyard/FEAT_closed.md').lane).toBe('graveyard');
expect(workspace.readFrontmatter('docs/method/graveyard/PROCESS_closed.md').lane).toBe('graveyard');
});
});
Loading
Loading