Re-scope transformation plan: protocol definitions only, implementations in separate repos#370
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Clarify repository scope: protocols vs implementations - Create TRANSFORMATION_PLAN_V2.md focused on protocol definitions - Create TECHNICAL_RECOMMENDATIONS_V2.md with protocol design examples - Update IMPLEMENTATION_CHECKLIST.md with clear Part A/B separation - Update EVALUATION_SUMMARY.md with architecture clarification - Archive original mixed-scope documents as backups Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
- Create DOCS_NAVIGATION.md to help users understand V2 changes - Explain repository scope separation (protocols vs implementations) - Provide reading paths for different audiences - Include quick stats and version history - Reference all V2 documents with their purposes Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
- Replace corrupted emoji character with proper UTF-8 target emoji - Address code review feedback Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
|
This PR is very large. Consider breaking it into smaller PRs for easier review. |
1 similar comment
|
This PR is very large. Consider breaking it into smaller PRs for easier review. |
d9f05d1
into
copilot/evaluate-source-code-optimizations
There was a problem hiding this comment.
Pull request overview
This PR re-scopes the transformation plan from PR #369 to correctly separate protocol definitions (which belong in this repository) from implementation work (which belongs in separate plugin repositories). The PR addresses user feedback that the original plan incorrectly proposed building drivers and plugins within the spec repository.
Changes:
- Created V2 versions of key documents focusing exclusively on protocol specifications
- Clearly delineated 31 protocol tasks for this repo vs 17+ implementation tasks for separate repos
- Provided comprehensive Zod schema examples for 9 critical missing protocols (GraphQL, Encryption, Cache, Search, Storage, etc.)
- Established architectural separation between
objectstack-ai/spec(protocols) andobjectstack-ai/driver-*/objectstack-ai/plugin-*(implementations)
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| TRANSFORMATION_PLAN_V2.md | 12-month protocol development roadmap with 4 phases, separating 31 protocol definition tasks from 17+ implementation repos |
| TECHNICAL_RECOMMENDATIONS_V2.md | Detailed Zod schema examples for missing protocols (GraphQL, Cache, Encryption, Compliance, etc.) with competitive analysis |
| IMPLEMENTATION_CHECKLIST.md | Two-part checklist: Part A (31 protocol tasks for this repo), Part B (17 implementation projects for separate repos) |
| EVALUATION_SUMMARY.md | Updated navigation and architecture clarification document explaining the protocol-only scope |
| DOCS_NAVIGATION.md | New navigation guide helping contributors understand V2 documents and reading paths for different personas |
| **Enhanced Protocol Files (10 files)**: | ||
| 1. `packages/spec/src/system/driver.zod.ts` (enhanced capabilities) | ||
| 2. `packages/spec/src/data/field.zod.ts` (encryption, masking, file attachments) | ||
| 3. `packages/spec/src/data/object.zod.ts` (multi-tenancy, partitioning, indexes) | ||
| 4. `packages/spec/src/auth/permission.zod.ts` (row-level security) | ||
| 5. `packages/spec/src/api/websocket.zod.ts` (enhanced real-time) | ||
| 6. `packages/spec/src/system/connector.zod.ts` (enhanced authentication) |
There was a problem hiding this comment.
Inconsistent count for enhanced protocol files. The header says "Enhanced Protocol Files (10 files)" but only 6 files are listed below (driver.zod.ts, field.zod.ts, object.zod.ts, permission.zod.ts, websocket.zod.ts, connector.zod.ts). Either add the missing 4 files to the list or update the count to "6 files".
| typeName: z.string(), | ||
| description: z.string().optional(), | ||
| fields: z.record(z.object({ | ||
| type: z.enum(['String', 'Int', 'Float', 'Boolean', 'ID', 'Custom']), | ||
| list: z.boolean().default(false), | ||
| nullable: z.boolean().default(true), | ||
| customType: z.string().optional(), | ||
| })), | ||
| }); | ||
|
|
||
| export const GraphQLQueryConfigSchema = z.object({ | ||
| enabled: z.boolean().default(true), | ||
| operationName: z.string(), | ||
| returnType: z.string(), | ||
| args: z.record(z.string()).optional(), | ||
| complexity: z.number().optional(), | ||
| }); | ||
|
|
||
| export const GraphQLMutationConfigSchema = z.object({ | ||
| enabled: z.boolean().default(true), | ||
| operationName: z.string(), | ||
| inputType: z.string(), | ||
| returnType: z.string(), | ||
| }); | ||
|
|
||
| export const GraphQLSubscriptionConfigSchema = z.object({ | ||
| enabled: z.boolean().default(false), | ||
| eventName: z.string(), | ||
| filter: z.string().optional(), | ||
| payload: z.string(), | ||
| }); | ||
|
|
||
| export const GraphQLConfigSchema = z.object({ | ||
| enabled: z.boolean().default(false), | ||
| endpoint: z.string().default('/graphql'), | ||
| playground: z.boolean().default(true), | ||
| introspection: z.boolean().default(true), | ||
| queryDepthLimit: z.number().default(10), | ||
| complexityLimit: z.number().default(1000), | ||
| queries: z.array(GraphQLQueryConfigSchema).optional(), | ||
| mutations: z.array(GraphQLMutationConfigSchema).optional(), | ||
| subscriptions: z.array(GraphQLSubscriptionConfigSchema).optional(), | ||
| }); |
There was a problem hiding this comment.
Missing .describe() calls for several schema properties. According to the repository's coding guidelines (see packages/spec/src/data/field.zod.ts), all schema properties should include descriptive .describe() calls for better documentation and IDE support. Properties missing descriptions include: typeName, list, nullable, enabled, operationName, returnType, and others in this schema.
| typeName: z.string(), | |
| description: z.string().optional(), | |
| fields: z.record(z.object({ | |
| type: z.enum(['String', 'Int', 'Float', 'Boolean', 'ID', 'Custom']), | |
| list: z.boolean().default(false), | |
| nullable: z.boolean().default(true), | |
| customType: z.string().optional(), | |
| })), | |
| }); | |
| export const GraphQLQueryConfigSchema = z.object({ | |
| enabled: z.boolean().default(true), | |
| operationName: z.string(), | |
| returnType: z.string(), | |
| args: z.record(z.string()).optional(), | |
| complexity: z.number().optional(), | |
| }); | |
| export const GraphQLMutationConfigSchema = z.object({ | |
| enabled: z.boolean().default(true), | |
| operationName: z.string(), | |
| inputType: z.string(), | |
| returnType: z.string(), | |
| }); | |
| export const GraphQLSubscriptionConfigSchema = z.object({ | |
| enabled: z.boolean().default(false), | |
| eventName: z.string(), | |
| filter: z.string().optional(), | |
| payload: z.string(), | |
| }); | |
| export const GraphQLConfigSchema = z.object({ | |
| enabled: z.boolean().default(false), | |
| endpoint: z.string().default('/graphql'), | |
| playground: z.boolean().default(true), | |
| introspection: z.boolean().default(true), | |
| queryDepthLimit: z.number().default(10), | |
| complexityLimit: z.number().default(1000), | |
| queries: z.array(GraphQLQueryConfigSchema).optional(), | |
| mutations: z.array(GraphQLMutationConfigSchema).optional(), | |
| subscriptions: z.array(GraphQLSubscriptionConfigSchema).optional(), | |
| }); | |
| typeName: z.string().describe('GraphQL type name (PascalCase, e.g., ProjectTask)'), | |
| description: z.string().optional().describe('Optional human-readable description for the GraphQL type'), | |
| fields: z | |
| .record( | |
| z.object({ | |
| type: z | |
| .enum(['String', 'Int', 'Float', 'Boolean', 'ID', 'Custom']) | |
| .describe('Scalar or custom GraphQL field type'), | |
| list: z | |
| .boolean() | |
| .default(false) | |
| .describe('Whether the field resolves to a list of values'), | |
| nullable: z | |
| .boolean() | |
| .default(true) | |
| .describe('Whether the field is nullable in the GraphQL schema'), | |
| customType: z | |
| .string() | |
| .optional() | |
| .describe('Name of a custom GraphQL type when type is "Custom"'), | |
| }), | |
| ) | |
| .describe('Map of field names to their GraphQL type configuration'), | |
| }).describe('Definition of a single GraphQL object type mapped from ObjectQL'); | |
| export const GraphQLQueryConfigSchema = z.object({ | |
| enabled: z | |
| .boolean() | |
| .default(true) | |
| .describe('Whether this GraphQL query operation is enabled'), | |
| operationName: z | |
| .string() | |
| .describe('GraphQL query operation name (field name on the Query root type)'), | |
| returnType: z | |
| .string() | |
| .describe('GraphQL return type for the query (e.g., ProjectTask, [ProjectTask])'), | |
| args: z | |
| .record(z.string()) | |
| .optional() | |
| .describe('Optional map of argument names to their GraphQL types'), | |
| complexity: z | |
| .number() | |
| .optional() | |
| .describe('Optional static complexity score for query cost analysis'), | |
| }).describe('Configuration for a single GraphQL query operation'); | |
| export const GraphQLMutationConfigSchema = z.object({ | |
| enabled: z | |
| .boolean() | |
| .default(true) | |
| .describe('Whether this GraphQL mutation operation is enabled'), | |
| operationName: z | |
| .string() | |
| .describe('GraphQL mutation operation name (field name on the Mutation root type)'), | |
| inputType: z | |
| .string() | |
| .describe('Input GraphQL type used as the mutation argument payload'), | |
| returnType: z | |
| .string() | |
| .describe('GraphQL return type for the mutation result'), | |
| }).describe('Configuration for a single GraphQL mutation operation'); | |
| export const GraphQLSubscriptionConfigSchema = z.object({ | |
| enabled: z | |
| .boolean() | |
| .default(false) | |
| .describe('Whether this GraphQL subscription operation is enabled'), | |
| eventName: z | |
| .string() | |
| .describe('Underlying event or channel name that triggers the subscription'), | |
| filter: z | |
| .string() | |
| .optional() | |
| .describe('Optional filter expression applied to subscription events'), | |
| payload: z | |
| .string() | |
| .describe('GraphQL type for the subscription payload'), | |
| }).describe('Configuration for a single GraphQL subscription operation'); | |
| export const GraphQLConfigSchema = z.object({ | |
| enabled: z | |
| .boolean() | |
| .default(false) | |
| .describe('Global flag to enable or disable the GraphQL API'), | |
| endpoint: z | |
| .string() | |
| .default('/graphql') | |
| .describe('HTTP endpoint path where the GraphQL API is exposed'), | |
| playground: z | |
| .boolean() | |
| .default(true) | |
| .describe('Whether to enable the interactive GraphQL playground UI'), | |
| introspection: z | |
| .boolean() | |
| .default(true) | |
| .describe('Whether schema introspection is allowed on the GraphQL endpoint'), | |
| queryDepthLimit: z | |
| .number() | |
| .default(10) | |
| .describe('Maximum allowed query depth to prevent overly nested queries'), | |
| complexityLimit: z | |
| .number() | |
| .default(1000) | |
| .describe('Maximum allowed query complexity score'), | |
| queries: z | |
| .array(GraphQLQueryConfigSchema) | |
| .optional() | |
| .describe('List of configured GraphQL query operations'), | |
| mutations: z | |
| .array(GraphQLMutationConfigSchema) | |
| .optional() | |
| .describe('List of configured GraphQL mutation operations'), | |
| subscriptions: z | |
| .array(GraphQLSubscriptionConfigSchema) | |
| .optional() | |
| .describe('List of configured GraphQL subscription operations'), | |
| }).describe('Top-level GraphQL server configuration for an ObjectStack package'); |
| ]); | ||
|
|
||
| export const CacheTierSchema = z.object({ | ||
| name: z.string(), | ||
| type: z.enum(['memory', 'redis', 'memcached', 'cdn']), | ||
| maxSize: z.number().optional().describe('Max size in MB'), | ||
| ttl: z.number().default(300).describe('Default TTL in seconds'), | ||
| strategy: CacheStrategySchema.default('lru'), | ||
| warmup: z.boolean().default(false), | ||
| }); | ||
|
|
||
| export const CacheInvalidationSchema = z.object({ | ||
| trigger: z.enum(['create', 'update', 'delete', 'manual']), | ||
| scope: z.enum(['key', 'pattern', 'tag', 'all']), | ||
| pattern: z.string().optional(), | ||
| tags: z.array(z.string()).optional(), | ||
| }); | ||
|
|
||
| export const CacheConfigSchema = z.object({ | ||
| enabled: z.boolean().default(false), | ||
| tiers: z.array(CacheTierSchema), | ||
| invalidation: z.array(CacheInvalidationSchema), | ||
| prefetch: z.boolean().default(false), | ||
| compression: z.boolean().default(false), | ||
| encryption: z.boolean().default(false), |
There was a problem hiding this comment.
Inconsistent use of .describe() calls. Some properties like maxSize and ttl have descriptions, but others like name, type, strategy, warmup do not. For consistency with the existing codebase patterns (see packages/spec/src/data/field.zod.ts), all properties should include descriptive .describe() calls.
| ]); | |
| export const CacheTierSchema = z.object({ | |
| name: z.string(), | |
| type: z.enum(['memory', 'redis', 'memcached', 'cdn']), | |
| maxSize: z.number().optional().describe('Max size in MB'), | |
| ttl: z.number().default(300).describe('Default TTL in seconds'), | |
| strategy: CacheStrategySchema.default('lru'), | |
| warmup: z.boolean().default(false), | |
| }); | |
| export const CacheInvalidationSchema = z.object({ | |
| trigger: z.enum(['create', 'update', 'delete', 'manual']), | |
| scope: z.enum(['key', 'pattern', 'tag', 'all']), | |
| pattern: z.string().optional(), | |
| tags: z.array(z.string()).optional(), | |
| }); | |
| export const CacheConfigSchema = z.object({ | |
| enabled: z.boolean().default(false), | |
| tiers: z.array(CacheTierSchema), | |
| invalidation: z.array(CacheInvalidationSchema), | |
| prefetch: z.boolean().default(false), | |
| compression: z.boolean().default(false), | |
| encryption: z.boolean().default(false), | |
| ]).describe('Cache eviction strategy for a given tier'); | |
| export const CacheTierSchema = z.object({ | |
| name: z.string().describe('Cache tier name (machine identifier, snake_case recommended)'), | |
| type: z | |
| .enum(['memory', 'redis', 'memcached', 'cdn']) | |
| .describe('Underlying cache backend type for this tier'), | |
| maxSize: z.number().optional().describe('Max size in MB for this cache tier'), | |
| ttl: z.number().default(300).describe('Default time-to-live (TTL) in seconds for cache entries'), | |
| strategy: CacheStrategySchema.default('lru').describe('Eviction strategy used by this cache tier'), | |
| warmup: z | |
| .boolean() | |
| .default(false) | |
| .describe('Whether to pre-warm this cache tier on startup or deployment'), | |
| }); | |
| export const CacheInvalidationSchema = z.object({ | |
| trigger: z | |
| .enum(['create', 'update', 'delete', 'manual']) | |
| .describe('Event that triggers cache invalidation'), | |
| scope: z | |
| .enum(['key', 'pattern', 'tag', 'all']) | |
| .describe('Scope of invalidation (single key, pattern, tag set, or all entries)'), | |
| pattern: z | |
| .string() | |
| .optional() | |
| .describe('Glob or regex-like pattern used when scope is pattern-based'), | |
| tags: z | |
| .array(z.string()) | |
| .optional() | |
| .describe('List of tags whose associated cache entries should be invalidated'), | |
| }); | |
| export const CacheConfigSchema = z.object({ | |
| enabled: z | |
| .boolean() | |
| .default(false) | |
| .describe('Whether caching is enabled for this service or manifest'), | |
| tiers: z | |
| .array(CacheTierSchema) | |
| .describe('Ordered list of cache tiers forming the caching hierarchy'), | |
| invalidation: z | |
| .array(CacheInvalidationSchema) | |
| .describe('Configured cache invalidation rules and triggers'), | |
| prefetch: z | |
| .boolean() | |
| .default(false) | |
| .describe('Whether to prefetch and cache data proactively (read-ahead)'), | |
| compression: z | |
| .boolean() | |
| .default(false) | |
| .describe('Enable compression for cached payloads'), | |
| encryption: z | |
| .boolean() | |
| .default(false) | |
| .describe('Enable encryption at rest for cached payloads'), |
| name: z.string(), | ||
| region: z.string().optional(), | ||
| public: z.boolean().default(false), | ||
| versioning: z.boolean().default(false), | ||
| encryption: z.enum(['none', 'aes256', 'kms']).default('none'), | ||
| lifecycle: z.object({ | ||
| expirationDays: z.number().optional(), | ||
| transitionToArchive: z.number().optional(), | ||
| }).optional(), | ||
| }); | ||
|
|
||
| export const PresignedUrlConfigSchema = z.object({ | ||
| expiration: z.number().default(3600).describe('Expiration in seconds'), | ||
| allowedOperations: z.array(z.enum(['get', 'put', 'delete'])), | ||
| }); | ||
|
|
||
| export const ObjectStorageConfigSchema = z.object({ | ||
| provider: StorageProviderSchema, | ||
| accessKeyId: z.string().optional(), | ||
| secretAccessKey: z.string().optional(), | ||
| endpoint: z.string().optional(), | ||
| buckets: z.array(BucketConfigSchema), | ||
| multipartThreshold: z.number().default(5242880).describe('5MB in bytes'), | ||
| presignedUrls: PresignedUrlConfigSchema.optional(), |
There was a problem hiding this comment.
Inconsistent use of .describe() calls. Properties like expiration, multipartThreshold have descriptions, but others like name, region, public, versioning, provider, accessKeyId, secretAccessKey, endpoint do not. All properties should have descriptive .describe() calls for consistency with established codebase patterns.
| name: z.string(), | |
| region: z.string().optional(), | |
| public: z.boolean().default(false), | |
| versioning: z.boolean().default(false), | |
| encryption: z.enum(['none', 'aes256', 'kms']).default('none'), | |
| lifecycle: z.object({ | |
| expirationDays: z.number().optional(), | |
| transitionToArchive: z.number().optional(), | |
| }).optional(), | |
| }); | |
| export const PresignedUrlConfigSchema = z.object({ | |
| expiration: z.number().default(3600).describe('Expiration in seconds'), | |
| allowedOperations: z.array(z.enum(['get', 'put', 'delete'])), | |
| }); | |
| export const ObjectStorageConfigSchema = z.object({ | |
| provider: StorageProviderSchema, | |
| accessKeyId: z.string().optional(), | |
| secretAccessKey: z.string().optional(), | |
| endpoint: z.string().optional(), | |
| buckets: z.array(BucketConfigSchema), | |
| multipartThreshold: z.number().default(5242880).describe('5MB in bytes'), | |
| presignedUrls: PresignedUrlConfigSchema.optional(), | |
| name: z.string().describe('Bucket machine name (snake_case identifier used in configs)'), | |
| region: z.string().optional().describe('Cloud region or location for the bucket'), | |
| public: z.boolean().default(false).describe('Whether objects in this bucket are publicly readable by default'), | |
| versioning: z.boolean().default(false).describe('Enable object versioning for this bucket'), | |
| encryption: z.enum(['none', 'aes256', 'kms']).default('none').describe('Server-side encryption strategy for objects in this bucket'), | |
| lifecycle: z.object({ | |
| expirationDays: z.number().optional().describe('Number of days before objects are permanently deleted'), | |
| transitionToArchive: z.number().optional().describe('Number of days before objects transition to colder/archive storage'), | |
| }).optional().describe('Lifecycle rules controlling retention and archival behavior'), | |
| }); | |
| export const PresignedUrlConfigSchema = z.object({ | |
| expiration: z.number().default(3600).describe('Expiration in seconds'), | |
| allowedOperations: z.array(z.enum(['get', 'put', 'delete'])).describe('List of HTTP/object operations allowed for the presigned URL'), | |
| }); | |
| export const ObjectStorageConfigSchema = z.object({ | |
| provider: StorageProviderSchema.describe('Object storage provider implementation to use'), | |
| accessKeyId: z.string().optional().describe('Access key or client ID used to authenticate with the storage provider'), | |
| secretAccessKey: z.string().optional().describe('Secret key or client secret used to authenticate with the storage provider'), | |
| endpoint: z.string().optional().describe('Custom endpoint URL for the storage provider (useful for MinIO/local stacks)'), | |
| buckets: z.array(BucketConfigSchema).describe('List of bucket configurations managed by this storage provider'), | |
| multipartThreshold: z.number().default(5242880).describe('Minimum object size in bytes before multipart upload is used (5MB default)'), | |
| presignedUrls: PresignedUrlConfigSchema.optional().describe('Defaults for presigned URL generation'), |
| export const ConnectorTemplateSchema = z.object({ | ||
| name: z.string(), | ||
| version: z.string(), | ||
| authMethod: AuthMethodSchema, | ||
| authConfig: z.union([ | ||
| OAuth2ConfigSchema, | ||
| z.object({ apiKey: z.string() }), | ||
| z.object({ username: z.string(), password: z.string() }), | ||
| ]), | ||
| endpoints: z.record(z.object({ | ||
| url: z.string(), | ||
| method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']), | ||
| headers: z.record(z.string()).optional(), | ||
| })), | ||
| fieldMappings: z.array(FieldMappingSchema), | ||
| syncConfig: SyncConfigSchema, | ||
| rateLimiting: z.object({ | ||
| requestsPerSecond: z.number(), | ||
| retryStrategy: z.enum(['exponential-backoff', 'linear', 'none']), | ||
| maxRetries: z.number().default(3), | ||
| }).optional(), | ||
| }); |
There was a problem hiding this comment.
The schema allows sensitive credentials (apiKey, password, clientSecret) to be defined as plain strings. While this is a protocol definition and not an implementation, consider adding a JSDoc comment or .describe() call indicating that implementations should handle these values securely (e.g., encryption at rest, secure key management). This would guide plugin implementers toward secure practices.
| enabled: z.boolean().default(false), | ||
| endpoint: z.string().default('/graphql'), | ||
| playground: z.boolean().default(true), | ||
| introspection: z.boolean().default(true), |
There was a problem hiding this comment.
GraphQL introspection enabled by default (introspection: z.boolean().default(true)) could pose a security risk in production environments as it exposes the entire schema to potential attackers. Consider defaulting to false and requiring explicit opt-in, or add a .describe() comment warning implementers to disable this in production.
| introspection: z.boolean().default(true), | |
| introspection: z.boolean().default(true).describe('WARNING: Enable GraphQL introspection only in non-production or tightly controlled environments; disable it in production to avoid exposing the full schema to potential attackers.'), |
| export const GraphQLConfigSchema = z.object({ | ||
| enabled: z.boolean().default(false), | ||
| endpoint: z.string().default('/graphql'), | ||
| playground: z.boolean().default(true), |
There was a problem hiding this comment.
GraphQL playground enabled by default (playground: z.boolean().default(true)) is convenient for development but should not be enabled in production. Consider defaulting to false or adding a .describe() comment warning implementers to disable this in production environments.
| playground: z.boolean().default(true), | |
| playground: z.boolean().default(false).describe('Enable GraphQL playground; should remain disabled in production environments'), |
| 19. `packages/spec/src/system/event-streaming.zod.ts` | ||
| 20. `packages/spec/src/system/time-series.zod.ts` | ||
| 21. `packages/spec/src/system/graph-database.zod.ts` | ||
| 22. `packages/spec/src/system/data-warehouse.zod.ts` |
There was a problem hiding this comment.
The list claims "New Protocol Files (21 files)" but actually lists 22 files (numbered 1-22). Either update the count to "22 files" or remove one duplicate entry from the list.
| 22. `packages/spec/src/system/data-warehouse.zod.ts` |
PR #369's transformation plan incorrectly proposed building drivers and plugins within the spec repository. This repo defines protocols (Zod schemas, TypeScript types, JSON schemas) — implementations belong in separate plugin repositories.
Changes
V2 Documents (protocol-focused)
TRANSFORMATION_PLAN_V2.md— 31 protocol definition tasks for this repo, references to 17+ implementation reposTECHNICAL_RECOMMENDATIONS_V2.md— Complete Zod schema examples for missing protocols (GraphQL, Encryption, Cache, etc.)IMPLEMENTATION_CHECKLIST.md— Part A: protocol work (this repo), Part B: driver/plugin work (separate repos)EVALUATION_SUMMARY.md— Architecture clarification and document navigationDOCS_NAVIGATION.md— Guide to all documents with reading pathsArchitecture Separation
Protocol Work Identified (this repo)
Example Protocol Definition
Original documents archived as
.backupfiles for reference.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.