Skip to content

spec(240): LinkML-derive @debrief/stac-writer contract types#604

Open
IanMayo wants to merge 5 commits intomainfrom
claude/start-speckit-240-DixZc
Open

spec(240): LinkML-derive @debrief/stac-writer contract types#604
IanMayo wants to merge 5 commits intomainfrom
claude/start-speckit-240-DixZc

Conversation

@IanMayo
Copy link
Copy Markdown
Member

@IanMayo IanMayo commented May 8, 2026

Summary

Add comprehensive specification and planning documentation for feature 240, which consolidates the PropertiesProvenanceEntry type 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 PropertiesProvenanceEntry as the canonical LinkML-derived type, with StacItem typing 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 StacItem typing is deferred, why a hybrid intersection preserves compile-time literal-string guards, generator determinism requirements, and reconciliation of the source enum divergence.

  • data-model.md: Type-level delta showing the three divergent PropertiesProvenanceEntry declarations 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.review plan 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.properties typing) and 097 add format menu #256 (defer prefix-aware TS emission for debrief:* fields).

Notable Details

  • The specification reflects material revisions from /speckit.review (2026-05-08): StacItem typing 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.
  • Phase 1 gates all subsequent work on verified generator determinism (SC-007), ensuring the CI drift check is safe to ship.
  • The hybrid intersection approach (Omit<Generated, 'tool' | 'method' | 'source'> & { tool: ...; method: ...; source: ... }) centralizes the LinkML re-export and literal narrowing in one place (@debrief/components/PropertiesPanel/provenanceTypes.ts).
  • A new workspace dependency edge (@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

claude added 4 commits May 7, 2026 16:51
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).
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-604 May 8, 2026 16:12 Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

📋 Backlog Navigator

Review this PR's BACKLOG.md edits interactively:

👉 Open in Backlog Navigator

Updated for 9392cce — the navigator reads BACKLOG.md live from this PR's head branch, so no rebuild is needed.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

📋 Spec Navigator

Review this PR's specs interactively:
👉 Open in Spec Navigator
Raw spec directories changed in this PR:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants