spec(240): LinkML-derive @debrief/stac-writer contract types#604
Open
spec(240): LinkML-derive @debrief/stac-writer contract types#604
Conversation
Closes the last hand-written gap on the writer's contract surface (per #236 review 2A) by wiring the existing LinkML generators (gen-typescript, gen-pydantic) into `@debrief/stac-writer`'s build. `PropertiesProvenanceEntry` is promoted from hand-written declaration in `apps/vscode/src/services/stacService.ts` to a concrete LinkML class. Spec: specs/240-linkml-stac-writer-types/spec.md Backlog: item 240 status proposed → specified
Phase 0 research surfaced a key factual update: `PropertiesProvenanceEntry`
already exists as a concrete LinkML class in `stac-extension.yaml`. The
work narrows from "add a class + rewrite types" to "re-point three TS
hand-writes at the existing canonical class, add a CI drift check, and
reconcile the dead-code `source` enum."
Three TS files modified, one CI workflow extended, one Taskfile target
added. No new packages, no new dependencies, no new LinkML classes,
no on-disk format changes.
R1: Don't add `StacItem` to LinkML — bare STAC 1.1 is upstream territory;
type the writer's `StacItem.properties` as
`StacExtensionProperties & Record<string, unknown>` instead.
R2: Accept literal-string widening from `gen-typescript`; runtime
validator stays as the enforcement gate.
R3: Drift check goes in `schema-tests.yml` (already runs the generator).
R4: Narrow writer's `source` enum from `'user'|'tool'|'import'` to
`'user'` — extra values are dead code.
R5: `linguist-generated=true` on generated artefacts for PR-diff hygiene.
Artefacts: plan.md, research.md, data-model.md, contracts/, quickstart.md,
evidence/opening-context.md.
…ion, drift-check determinism gate Six decisions applied across the spec/plan/research/data-model/contracts/quickstart: 1. StacItem typing dropped from this feature. The originally-planned `properties: StacExtensionProperties & Record<string, unknown>` would deliver no value because LinkML's gen-typescript strips the `debrief:` JSON-key prefix; the writer accesses `properties` by JSON key (`props['debrief:provenance_log']`), which falls into the index signature and bypasses the named slots. Captured as #255 backlog. 2. PropertiesProvenanceEntry adopts a hybrid intersection in shared/components/src/PropertiesPanel/provenanceTypes.ts: Omit<Generated, 'tool'|'method'|'source'> & { tool: typeof PROPERTIES_PANEL_TOOL_SENTINEL; method: `properties-panel@${string}`; source: 'user'; } Preserves the LinkML link AND the compile-time guard that today's production write sites (stacService.ts:1323, stacWriterIdb.ts:332) rely on. The runtime validator is only called in tests, so accepting loose types would have re-opened an Article I.3 silent-failure path. 3. Workspace dep edge `@debrief/stac-writer → @debrief/components` accepted (type-only via subpath leaf; ESLint bans runtime imports). 4. Spec FR-001/FR-003 reconciled. FR-001 narrows to PropertiesProvenanceEntry only. FR-003 reframes from "add a class" to "verify-canonical and re-point" since the LinkML class already exists. Story 1 rewritten around consolidation; old Story 2 redundant and removed. SC-005 reframed (StacItem is a tracked deferral, not an open audit finding). SC-007 added — generator determinism is a P0 gate before drift check ships. 5. Generator determinism becomes a quickstart Step 2 (gates Step 3 / drift). 6. Two backlog items captured: - #255 Prefix-aware TS typing for StacExtensionProperties (Medium) - #256 Production read-path runtime validation of provenance entries (Low) BACKLOG.md row 240 description updated to reflect reduced scope.
Phase 1 (P0 gate, 1 task): Verify generator determinism (SC-007). Gates everything else; if non-deterministic, normalisation pass lands in the same change before the drift check ships. Phase 2 (Foundation, 4 tasks): Workspace dep edge in writer's package.json, ESLint no-restricted-imports rule for type-only edge, .gitattributes linguist-generated marker, plus verification. Phase 3 (Story 1, 7 tasks): Hybrid intersection in components-side provenanceTypes.ts, delete writer's hand-written declaration, then five parallel verification steps (audit, typecheck, vscode unit tests, Python round-trip, new TS-side smoke test). Phase 4 (Story 2, 4 tasks): Drift step in schema-tests.yml, Taskfile targets, local check, then deliberate-drift CI walkthrough on a throwaway branch (proves SC-003). Phase 5 (Polish, 10 tasks): Seven evidence artefacts (mostly parallel confirmation against earlier phase outputs), full task verify, blog post via Content Specialist (extends the cached opener), final /speckit.pr. Total: 26 tasks. Estimated effort ~2 dev-days. No screenshots, no GIF (backend feature, zero visual surface).
…240-DixZc # Conflicts: # BACKLOG.md
Contributor
📋 Backlog NavigatorReview this PR's BACKLOG.md edits interactively: Updated for 9392cce — the navigator reads BACKLOG.md live from this PR's head branch, so no rebuild is needed. |
Contributor
📋 Spec NavigatorReview this PR's specs interactively:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add comprehensive specification and planning documentation for feature 240, which consolidates the
PropertiesProvenanceEntrytype definition by routing it through LinkML instead of maintaining three divergent hand-written TypeScript declarations.Changes
This PR introduces the complete specification package for the LinkML-derivation feature:
spec.md: Feature specification with user stories, functional requirements, and success criteria. Defines the consolidation of
PropertiesProvenanceEntryas the canonical LinkML-derived type, withStacItemtyping deferred to a follow-up.plan.md: Implementation plan detailing the technical approach (hybrid intersection pattern for
PropertiesProvenanceEntry, CI drift gate, workspace dependency edge), scope reductions from/speckit.review, and phased execution strategy.research.md: Investigation outcomes (R1–R5) documenting why
StacItemtyping is deferred, why a hybrid intersection preserves compile-time literal-string guards, generator determinism requirements, and reconciliation of thesourceenum divergence.data-model.md: Type-level delta showing the three divergent
PropertiesProvenanceEntrydeclarations today and the target state (one LinkML-generated body + hybrid intersection in components + re-export in writer).quickstart.md: Local validation walkthrough with 10 steps mapping to functional requirements and success criteria, including generator determinism verification, drift check provocation, and round-trip testing.
tasks.md: Detailed task list executing the post-
/speckit.reviewplan across 5 phases (determinism gate, foundation, user story 1, integration, shipping), with evidence requirements and artifact capture templates.contracts/stac-writer-public-types.md: Binding TypeScript public-surface contract pinning the expected output shapes for
PropertiesProvenanceEntry,StacItem, and the CI drift check.evidence/opening-context.md: Cached context (hook, what we're building, how it fits, key decisions) for later publication.
checklists/requirements.md: Specification quality validation checklist confirming completeness and testability.
BACKLOG.md: Added backlog entries feat: 095 add polygon and polyline drawing support #255 (defer
StacItem.propertiestyping) and 097 add format menu #256 (defer prefix-aware TS emission fordebrief:*fields).Notable Details
/speckit.review(2026-05-08):StacItemtyping is deferred, and a hybrid intersection pattern is adopted to preserve compile-time literal-string guards at production write sites while still routing through LinkML.Omit<Generated, 'tool' | 'method' | 'source'> & { tool: ...; method: ...; source: ... }) centralizes the LinkML re-export and literal narrowing in one place (@debrief/components/PropertiesPanel/provenanceTypes.ts).@debrief/stac-writer → @debrief/components, type-only) is introduced with an ESLint rule to keep it type-only and prevent runtime coupling.https://claude.ai/code/session_01Ggv3zZiRbfJxa68y3txvwK