Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9f3c6dc
test(diagnostics): define strict host diagnostic contract
seonghobae Aug 12, 2026
52c1ae4
ci(diagnostics): verify contract TDD red-green cycle
seonghobae Aug 12, 2026
67c5ac8
feat(diagnostics): add strict writing diagnostic contract
seonghobae Aug 12, 2026
68c8665
test(diagnostics): apply stricter limit in its own assertion
seonghobae Aug 12, 2026
8b60c14
test(diagnostics): require root and framework-free exports
seonghobae Aug 12, 2026
dfc8a8d
ci(diagnostics): verify source export contract
seonghobae Aug 12, 2026
6a2cae5
feat(diagnostics): add framework-free source subpath
seonghobae Aug 12, 2026
bae0d55
feat(diagnostics): export host diagnostic contract
seonghobae Aug 12, 2026
ce38a45
ci(diagnostics): enforce exact contract coverage
seonghobae Aug 12, 2026
9bb0117
ci(diagnostics): report uncovered contract paths
seonghobae Aug 12, 2026
246614a
test(diagnostics): cover hostile structural boundaries
seonghobae Aug 12, 2026
a38d3d4
ci(diagnostics): exercise hostile contract boundaries
seonghobae Aug 12, 2026
1cf16ac
refactor(diagnostics): remove unreachable validation branches
seonghobae Aug 12, 2026
67b0e56
test(diagnostics): keep missing-field fixture type-safe
seonghobae Aug 12, 2026
7c8dd98
ci(diagnostics): run full package acceptance
seonghobae Aug 12, 2026
c0baa93
docs(adr): restore canonical quality contract
seonghobae Aug 12, 2026
fa05e84
Merge design/llm-writing-diagnostics into feat/writing-diagnostics-co…
seonghobae Aug 12, 2026
6697bfe
docs(adr): inherit strict diagnostics v1 decision
seonghobae Aug 12, 2026
ba37c4d
docs(plan): inherit strict diagnostics v1 errata
seonghobae Aug 12, 2026
322c838
Merge design/llm-writing-diagnostics into feat/writing-diagnostics-co…
seonghobae Aug 12, 2026
525400d
docs(diagnostics): reconcile contract with current design
seonghobae Aug 13, 2026
0706e0d
chore(diagnostics): inherit unique ADR numbering
seonghobae Aug 16, 2026
0bbd3f3
chore(diagnostics): inherit release workflow repair
seonghobae Aug 16, 2026
e80545e
merge(parent): synchronize writing diagnostics contract lane
seonghobae Aug 18, 2026
81fbd55
test(package): require writing diagnostics subpath publication
seonghobae Aug 25, 2026
b878721
test(diagnostics): keep package publication on package owner
seonghobae Aug 25, 2026
2322356
merge(stack): synchronize diagnostics contract with current root
seonghobae Aug 28, 2026
4ec9676
Merge remote-tracking branch 'origin/design/llm-writing-diagnostics' …
seonghobae Sep 4, 2026
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
130 changes: 130 additions & 0 deletions .github/workflows/writing-diagnostics-contract-tdd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Writing Diagnostics Contract TDD

on:
push:
branches:
- feat/writing-diagnostics-contract
workflow_dispatch:

permissions:
contents: read

concurrency:
group: writing-diagnostics-contract-tdd-${{ github.ref }}
cancel-in-progress: true

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
focused-contract:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
persist-credentials: false
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Collect focused contract coverage
id: focused_coverage
continue-on-error: true
run: >-
pnpm exec vitest run
src/writingDiagnostics.test.ts
src/writingDiagnosticsBoundary.test.ts
src/writingDiagnosticsExports.test.ts
--coverage
--coverage.include=src/writingDiagnostics.ts
--coverage.reporter=text
--coverage.reporter=json
--coverage.reporter=json-summary
- name: Report and enforce exact contract coverage
run: |
node <<'NODE'
const { readFileSync } = require('node:fs');
const coverage = JSON.parse(readFileSync('coverage/coverage-final.json', 'utf8'));
const [filePath, fileCoverage] = Object.entries(coverage).find(
([candidate]) => candidate.endsWith('/src/writingDiagnostics.ts'),
) ?? [];
if (!filePath || !fileCoverage) {
console.error('::error file=src/writingDiagnostics.ts,line=1::Focused coverage record is missing.');
process.exit(1);
}

const missingStatementLines = [...new Set(
Object.entries(fileCoverage.s)
.filter(([, count]) => count === 0)
.map(([id]) => fileCoverage.statementMap[id].start.line),
)].sort((a, b) => a - b);
const missingFunctionLines = [...new Set(
Object.entries(fileCoverage.f)
.filter(([, count]) => count === 0)
.map(([id]) => fileCoverage.fnMap[id].decl.start.line),
)].sort((a, b) => a - b);
const missingBranches = [];
for (const [id, counts] of Object.entries(fileCoverage.b)) {
counts.forEach((count, index) => {
if (count === 0) {
const branch = fileCoverage.branchMap[id];
const location = branch.locations?.[index] ?? branch.loc;
missingBranches.push(`${location.start.line}:${index}`);
}
});
}

const total = (values) => Object.values(values).reduce(
(sum, value) => sum + (Array.isArray(value) ? value.length : 1),
0,
);
const covered = (values) => Object.values(values).reduce(
(sum, value) => sum + (Array.isArray(value)
? value.filter((count) => count > 0).length
: Number(value > 0)),
0,
);
const statementTotal = total(fileCoverage.s);
const statementCovered = covered(fileCoverage.s);
const functionTotal = total(fileCoverage.f);
const functionCovered = covered(fileCoverage.f);
const branchTotal = total(fileCoverage.b);
const branchCovered = covered(fileCoverage.b);
console.log(
`::notice file=src/writingDiagnostics.ts,line=1::` +
`Statements ${statementCovered}/${statementTotal}; ` +
`functions ${functionCovered}/${functionTotal}; ` +
`branches ${branchCovered}/${branchTotal}.`,
);

if (
missingStatementLines.length ||
missingFunctionLines.length ||
missingBranches.length ||
process.env.FOCUSED_COVERAGE_OUTCOME !== 'success'
) {
console.error(
`::error file=src/writingDiagnostics.ts,line=1::` +
`Missing statement lines: ${missingStatementLines.join(', ') || 'none'}; ` +
`missing function lines: ${missingFunctionLines.join(', ') || 'none'}; ` +
`missing branches line:index: ${missingBranches.join(', ') || 'none'}.`,
);
process.exit(1);
}
NODE
env:
FOCUSED_COVERAGE_OUTCOME: ${{ steps.focused_coverage.outcome }}
- name: Typecheck public source contracts
run: pnpm typecheck
- name: Run complete production coverage gate
run: pnpm coverage
- name: Build all package entrypoints
run: pnpm build
- name: Verify isolated package consumers
run: pnpm verify:package
- name: Build the demonstration application
run: pnpm build:demo
14 changes: 14 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ export type {
TextPositionSelectorEvidenceErrorCode,
} from './textPositionSelectorEvidence.js';

// Host-owned, revision-scoped writing diagnostic contract.
export {
DEFAULT_WRITING_DIAGNOSTIC_LIMITS,
WritingDiagnosticError,
validateWritingDiagnostics,
} from './writingDiagnostics.js';
export type {
CwlWritingDiagnostic,
CwlWritingDiagnosticPriority,
CwlWritingDiagnosticProvenance,
WritingDiagnosticErrorCode,
WritingDiagnosticLimits,
} from './writingDiagnostics.js';

// Versioned, lossless persistence boundary.
export {
DEFAULT_DOCUMENT_ENVELOPE_LIMITS,
Expand Down
19 changes: 19 additions & 0 deletions src/writing-diagnostics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Framework-independent public surface for host-supplied writing diagnostics.
*
* This subpath validates bounded revision-scoped diagnostic proposals. It does
* not import React, create editor instances, call models/providers or networks,
* persist authored content, infer language quality, or mutate a document.
*/
export {
DEFAULT_WRITING_DIAGNOSTIC_LIMITS,
WritingDiagnosticError,
validateWritingDiagnostics,
} from '../writingDiagnostics.js';
Comment thread
seonghobae marked this conversation as resolved.
export type {
CwlWritingDiagnostic,
CwlWritingDiagnosticPriority,
CwlWritingDiagnosticProvenance,
WritingDiagnosticErrorCode,
WritingDiagnosticLimits,
} from '../writingDiagnostics.js';
Loading
Loading