-
Notifications
You must be signed in to change notification settings - Fork 0
drive: cloud run af22a9cf #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,49 +1,73 @@ | ||
| # NEXT — Gate 3: Build the work package consumer | ||
| # NEXT — Consumer validates files_in_scope paths exist | ||
|
|
||
| **Scope:** Gate 3 — close the Garden's loop. CODE task, SDK-side. The picker EMITS a work package (sdk/src/backlog-picker.ts + testdata/backlog-picker.flow.yaml, merged, four tested properties) and NOTHING consumes it — that is the missing half. Build the consumer: an SDK entrypoint taking an emitted package and turning it into something runnable, validating it has a title, a non-empty scope and a definition of done, and REFUSING with a typed reason when it does not, because a package that cannot be verified must not become work. NOTE: two previous attempts (ee5c9b3e, 06c0d6ab) did this correctly and their files were LOST before delivery by a platform fault — the build sandbox's .git points at a directory that does not exist, so writes cannot be captured. You are not duplicating live work. | ||
| ## Target scope (from gate 3) | ||
|
|
||
| ## Objective | ||
| **Scope:** Harden the Garden's loop with a case it does not yet handle. CODE task, SDK-side. | ||
|
|
||
| On main now, all merged and tested: | ||
| - `sdk/src/backlog-picker.ts` — proposes a work package from ops/BACKLOG.md | ||
| - `sdk/src/work-package-consumer.ts` — judges one, refusing with a typed | ||
| reason (missing_title / missing_scope / missing_definition_of_done) | ||
| - `testdata/backlog-picker.flow.yaml` — the flow, with its canonical spec | ||
| - a test running the flow's real emit-package output through the consumer, | ||
| proving the two halves interoperate in both directions | ||
|
|
||
| So propose -> judge -> accept/refuse works end to end. What it does NOT do is | ||
| survive a hostile or malformed backlog. Pick ONE of these and do it properly: | ||
|
|
||
| (a) The picker reads whatever ops/BACKLOG.md contains. A malformed entry — a | ||
| bold title with no body, an unterminated backtick, a bullet nested under | ||
| another — should produce a typed refusal, never a crash and never a | ||
| half-formed package. Add the handling and the tests. | ||
|
|
||
| Build the SDK entrypoint that takes an emitted work package and turns it into something runnable. The consumer must validate that the package has: | ||
| - A title (non-empty string) | ||
| - A non-empty scope | ||
| - A definition of done | ||
| (b) The consumer accepts any package whose fields are present. It does not | ||
| check that files_in_scope names paths that EXIST, so a package can be | ||
| accepted while scoping files that are not there. Add that check as a new | ||
| typed refusal reason, with tests. | ||
|
|
||
| **Decision:** Implementing option (b) — files_in_scope path existence validation. | ||
|
|
||
| ## Objective | ||
|
|
||
| When any of these is missing or invalid, the consumer REFUSES with a typed reason. A package that cannot be verified must not become work. | ||
| Add a new refusal reason to `work-package-consumer.ts` that rejects packages | ||
| scoping nonexistent files. A package accepted today while naming files that do | ||
| not exist (`sdk/src/does-not-exist.ts`) must be refused with a typed reason | ||
| (`nonexistent_files`). | ||
|
|
||
| ## Files in scope | ||
|
|
||
| - `sdk/src/` (new consumer code) | ||
| - `sdk/tests/` (new consumer tests) | ||
| - NO changes to `kernel/` (PR #19 is open) | ||
| - NO changes to `sdk/src/demo-hn-monitor.ts` (PR #19 is open) | ||
| - `sdk/src/work-package-consumer.ts` | ||
| - `sdk/tests/work-package-consumer.test.ts` | ||
| - `sdk/src/index.ts` (if new types need export) | ||
|
|
||
| ## Definition of done | ||
|
|
||
| 1. **SDK code exists** that consumes an emitted work package | ||
| 2. **Validation tests exist** for: | ||
| - Missing title → typed refusal | ||
| - Empty title → typed refusal | ||
| - Missing scope → typed refusal | ||
| - Empty scope → typed refusal | ||
| - Missing definition of done → typed refusal | ||
| - Empty definition of done → typed refusal | ||
| - Valid package → accepted | ||
| 3. **Every new test is confirmed to FAIL against current code** with literal output pasted | ||
| 4. **SDK test suite passes:** | ||
| 1. **New typed refusal reason** `nonexistent_files` added to | ||
| `WorkPackageRefusalReason` type | ||
| 2. **Path existence check** in `consumeWorkPackage` that refuses when | ||
| files_in_scope contains paths that do not exist on disk | ||
| 3. **Tests covering the new behavior:** | ||
| - Test: refuse a package with all nonexistent files | ||
| - Test: refuse a package with a mix of existent and nonexistent files | ||
| - Test: accept a package with all existent files | ||
| 4. **EVERY new test confirmed to FAIL against current code** — the literal | ||
| failing output must be quoted below when reporting BUILD_DONE | ||
| 5. **Existing tests still passing** — all 8 existing work-package-consumer tests | ||
| green | ||
| 6. **Full SDK suite passing:** | ||
| ``` | ||
| cd sdk && npm test | ||
| ``` | ||
| Paste the literal output showing all tests pass, 0 failed | ||
| 5. **Final verification** — as the LAST action, run: | ||
| Must show green suite with exact pass count. | ||
| 7. **As the LAST action, run and paste:** | ||
| ``` | ||
| git status --porcelain | ||
| ``` | ||
| And paste the output to make lost writes visible immediately | ||
|
|
||
| ## Out of scope | ||
|
|
||
| - Kernel changes (different PR) | ||
| - Integration with hn-monitor (different PR) | ||
| - Any changes to the backlog picker itself (already merged in PRs #20, #21, #22) | ||
| - Changes to flow execution or scheduling | ||
| - Picker malformed-entry handling (option a) — that is NOT this run's target | ||
| - Checking that files are readable, only that they exist | ||
| - Recursively resolving directory globs — check the literal path only | ||
| - Any changes to kernel/, testdata/, or ops/ | ||
| - Any changes to sdk/src/demo-hn-monitor.ts |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| import { existsSync } from 'node:fs'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| /** The work-package shape emitted at the SDK boundary. */ | ||
| export interface EmittedWorkPackage { | ||
| title: string; | ||
|
|
@@ -10,7 +13,8 @@ export interface EmittedWorkPackage { | |
| export type WorkPackageRefusalReason = | ||
| | 'missing_title' | ||
| | 'missing_scope' | ||
| | 'missing_definition_of_done'; | ||
| | 'missing_definition_of_done' | ||
| | 'nonexistent_files'; | ||
|
|
||
| export type WorkPackageConsumption = | ||
| | { accepted: true; work: EmittedWorkPackage } | ||
|
|
@@ -30,9 +34,18 @@ export function consumeWorkPackage(input: unknown): WorkPackageConsumption { | |
| if (!isNonEmptyStringArray(input['definition_of_done'])) { | ||
| return { accepted: false, reason: 'missing_definition_of_done' }; | ||
| } | ||
| if (!input['files_in_scope'].every(pathExists)) { | ||
| return { accepted: false, reason: 'nonexistent_files' }; | ||
| } | ||
| return { accepted: true, work: input as unknown as EmittedWorkPackage }; | ||
| } | ||
|
|
||
| const repositoryRoot = new URL('../../', import.meta.url); | ||
|
|
||
| function pathExists(path: string): boolean { | ||
| return existsSync(fileURLToPath(new URL(path, repositoryRoot))); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For an absolute path or a path containing enough Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an otherwise well-shaped package contains URL-sensitive input such as Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| function isRecord(value: unknown): value is Record<string, unknown> { | ||
| return typeof value === 'object' && value !== null && !Array.isArray(value); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this SDK consumes a package for another checkout or temporary worktree, this root is derived from the SDK module's installation location rather than the workspace containing the scoped files. Consequently, a real file such as
src/only-here.tsin the target checkout is refused, while a same-named file in this repository can be accepted; an installed scoped package makes../../resolve insidenode_modules/@relayflowsinstead. The Garden join test masks this by running the picker in a temporary directory but changing its emitted path to one that exists only in the flows checkout.Useful? React with 👍 / 👎.